7

我正在尝试执行以下操作(仅以下代码的相关部分):

template<typename ContainerType>
struct IsContainerCheck : is_container<ContainerType>
{
   static constexpr char* err_value = "Type is not a container model";
};

namespace _check_concept {
    template<typename ResultType>
    struct run {
        constexpr static int apply() {
            static_assert(false, IsContainerCheck<ResultType>::err_value)
            return 0;
        }
    };

    template<>
    struct run<true_t> {
        constexpr static int apply() {
            return 0;
        }
    };
}

这失败了,因为 static_assert 只允许打印文字。BOOST_STATIC_ASSERT_MSG 宏也是如此。

所以我的问题是 - 有没有办法在编译期间输出 constexpr 字符串?如果有提供此功能的 gcc 扩展,那也很棒。

使用的编译器 gcc 4.8.1

4

2 回答 2

6

GCC 没有提供您想要的这种机制。但是,如果您能够按照以下程序所示的方式重构代码,则不需要它。(我已经填补了一些空白,以便给我们一个可编译的例子):

#include <type_traits>
#include <vector>

template<typename ContainerType>
struct is_container
{
    static bool const value = false;
};

template<>
struct is_container<std::vector<int>>
{
    static bool const value = true;
};

template<typename ContainerType>
struct IsContainerCheck // : is_container<ContainerType> <- Uneccessary
{
    static_assert(is_container<ContainerType>::value, 
        "Type is not a container model");
};

namespace _check_concept {
    template<typename ResultType>
    struct run {
        constexpr static int apply() {
            return (IsContainerCheck<ResultType>(),0);
        }
    };

    // No such specialization is necessary. Delete it.
    // template<>
    // struct run<true_t> {
    //    constexpr static int apply() {
    //        return 0;
    //    }
    //};
}

using namespace _check_concept;

int main(int argc, char **argv)
{
    auto verdict0 = run<std::vector<int>>::apply();
    (void)verdict0;
    // The following line will static_assert: "Type is not a container model"
    auto verdict1 = run<float>::apply();
    (void)verdict1;
    return 0;
}

在您的专业_check_concept::struct run<true_t>中,我认为这 不是true_t的别名或等效项,而只是某些容器类型的占位符。正如测试程序显示的那样,现在不需要这样的专业化,因为 在 unspecialized 中是否会取决于。std::true_typeResultTypeIsContainerCheck<ResultType>()static_assertResultTyperun<ResultType>::apply()

于 2013-07-18T17:12:24.797 回答
0

I had some time (and a good liqueur to come along with it) to think more about the problem. This is what I came up with:

namespace _details {
  struct PassedCheck {
    constexpr static int printError () {
      return 0; //no error concept check passed
    }
  };

  template<template<typename> class ConceptCheck, typename ...ModelTypes>
  struct check_concept_impl;

  template<template<typename> class ConceptCheck, typename FirstType, typename ...ModelTypes>
  struct check_concept_impl<ConceptCheck, FirstType, ModelTypes...> : mpl::eval_if< typename ConceptCheck<FirstType>::type,
                                                                    check_concept_impl<ConceptCheck, ModelTypes...>,
                                                                    mpl::identity<ConceptCheck<FirstType>>>
  { };

  template<template<typename> class ConceptCheck, typename LastType>
  struct check_concept_impl<ConceptCheck, LastType> : mpl::eval_if<typename ConceptCheck<LastType>::type,
                                                                mpl::identity<PassedCheck>,
                                                                mpl::identity<ConceptCheck<LastType>>>
  { };


}

template<template<typename> class ConceptCheck, typename ...ModelTypes>
struct check_concept {
private:
  typedef typename _details::check_concept_impl<ConceptCheck, ModelTypes...>::type      result_type;

public:
// the constexpr method assert produces shorter, fixed depth (2) error messages than a nesting assert in the trait solution
// the error message is not trahsed with the stack of variadic template recursion
  constexpr static int apply() {
    return result_type::printError();
  }
};


template<typename ContainerType>
struct IsContainerCheck : is_container<ContainerType>
{
    template<typename BoolType = false_t>
    constexpr static int printError () {
        static_assert(BoolType::value, "Type is not a container model");
        return 0;
    }
};

and the usage:

check_concept<IsContainerCheck, std::vector<int>, std::vector<int>, float, int>::apply(); 

The solution is probably not the most elegant one but I it keeps the assert message short:

In file included from ../main.cpp:4:0: ../constraint.check.hpp: In instantiation of ‘static constexpr int IsContainerCheck::printError() [with BoolType = std::integral_constant; ContainerType = float]’: ../constraint.check.hpp:61:34: required from ‘static constexpr int check_concept::apply() [with ConceptCheck = IsContainerCheck; ModelTypes = {std::vector >, std::vector >, float, int}]’ ../main.cpp:25:83: required from here ../constraint.check.hpp:74:3: error: static assertion failed: Type is not a container model static_assert(BoolType::value, "Type is not a container model");

The assert is issued in a constexpr method after the check_concept template specialization has been done. Embedding the static assert directly into the template class definition would drag the whole check_concept_impl recursion stack into the error message.

So changing the IsContainerCheck trait to something like (rest of the changes omitted for readibility):

template<typename ContainerType>
struct IsContainerCheck
{
static_assert(is_container<ContainerType>::type::value, "Type is not a container model");
};

would yield an error

../constraint.check.hpp: In instantiation of ‘struct IsContainerCheck’: ../constraint.check.hpp:36:9: required from ‘struct _details::check_concept_impl’ /usr/include/boost/mpl/eval_if.hpp:38:31: required from ‘struct boost::mpl::eval_if, _details::check_concept_impl, boost::mpl::identity > > >’ ../constraint.check.hpp:36:9: required from ‘struct _details::check_concept_impl >, float, int>’ /usr/include/boost/mpl/eval_if.hpp:38:31: required from ‘struct boost::mpl::eval_if, _details::check_concept_impl >, float, int>, boost::mpl::identity > > >’ ../constraint.check.hpp:36:9: required from ‘struct _details::check_concept_impl >, std::vector >, float, int>’ ../constraint.check.hpp:53:84: required from ‘struct check_concept >, std::vector >, float, int>’ ../main.cpp:25:81: required from here ../constraint.check.hpp:72:2: error: static assertion failed: Type is not a container model static_assert(is_container::type::value, "Type is not a container model");

As you can see each recursive eval_if call is emended in the error description which is bad because it makes the error message dependent from the amount and type of template parameters.

于 2013-07-18T20:08:34.263 回答