有没有办法在编译期间打印constexpr字符串?

时间:2013-07-18 10:19:33

标签: c++11

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

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

2 个答案:

答案 0 :(得分: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 不是别名或等同于std::true_type,而是。{ 只是某些ResultType的占位符,它是一种容器类型。如 测试程序显示,现在不需要这样的专业化,因为 IsContainerCheck<ResultType>()static_assert取决于ResultType run<ResultType>::apply()上的非专业{{1}}。

答案 1 :(得分:0)

我有一些时间(和一个好的利口酒一起来)来思考这个问题。这就是我想出的:

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;
    }
};

和用法:

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

解决方案可能不是最优雅的解决方案,但我保持断言信息简短:

  

在../main.cpp:4:0中包含的文件中:   ../constraint.check.hpp:实例化'static constexpr int IsContainerCheck :: printError()[with BoolType = std :: integral_constant; ContainerType = float]':   ../constraint.check.hpp:61:34:需要来自'static constexpr int check_concept :: apply()[with ConceptCheck = IsContainerCheck; ModelTypes = {std :: vector&gt;,std :: vector&gt;,float,int}]'   ../main.cpp:25:83:从这里要求   ../constraint.check.hpp:74:3:错误:静态断言失败:类型不是容器模型      static_assert(BoolType :: value,“Type不是容器模型”);

在check_concept模板专门化完成后,在constexpr方法中发出assert。将静态断言直接嵌入到模板类定义中会将整个check_concept_impl递归堆栈拖到错误消息中。

因此将IsContainerCheck特性更改为类似的内容(为了可读性而省略了其余的更改):

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

会产生错误

  

../ constraint.check.hpp:在'struct IsContainerCheck'的实例化中:   ../constraint.check.hpp:36:9:'struct _details :: check_concept_impl'需要   /usr/include/boost/mpl/eval_if.hpp:38:31:需要'struct boost :: mpl :: eval_if,_details :: check_concept_impl,boost :: mpl :: identity&gt; &GT; &GT;”   ../constraint.check.hpp:36:9:需要'struct _details :: check_concept_impl&gt;,float,int&gt;'   /usr/include/boost/mpl/eval_if.hpp:38:31:需要'struct boost :: mpl :: eval_if,_details :: check_concept_impl&gt;,float,int&gt ;, boost :: mpl :: identity&gt; &GT; &GT;”   ../constraint.check.hpp:36:9:需要'struct _details :: check_concept_impl&gt;,std :: vector&gt;,float,int&gt;'   ../constraint.check.hpp:53:84:需要'struct check_concept&gt;,std :: vector&gt;,float,int&gt;'   ../main.cpp:25:81:从这里要求   ../constraint.check.hpp:72:2:错误:静态断言失败:类型不是容器模型     static_assert(is_container :: type :: value,“Type不是容器模型”);

正如您所看到的,每个递归eval_if调用都在错误描述中被修改,这是错误的,因为它使错误消息依赖于模板参数的数量和类型。