Is there a way to print the string constexpr at compile time?

I am trying to do the following (only relevant parts of the code below):

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

This fails because static_assert allows only literals to be printed. Same thing with the BOOST_STATIC_ASSERT_MSG macro.

So my question is: is there a way to output the constexpr string at compile time? If there is a gcc extension providing this functionality, it would also be great.

Used gcc 4.8.1 compiler

+7
c ++ 11
source share
2 answers

GCC does not provide the mechanism you want. However, you will not need this if you are able to reorganize your code somewhat, as shown in the following program. (I filled in a few spaces to give us a compiled example):

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

In your specialization, _check_concept::struct run<true_t> I believe that true_t not an alias or equivalent to std::true_type , but rather just a place holder for some ResultType , which is a container type. In the form, the testing program shows that such specialization is not required now, because IsContainerCheck<ResultType>() will be static_assert or not, depending on ResultType , in the unspecialized run<ResultType>::apply() .

+6
source share

I had some time (and a good liquor to come along with it) to think more about the problem. Here 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 use:

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

The solution is probably not the most elegant, but I keep a short assert message:

It is included in the file from .. /main.cpp:407:../constraint.check.hpp: when creating '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//: error: static statement failed: Type is not a container model static_assert (BoolType :: value, "Type is not a container model");

The statement is issued in the constexpr method after the check_concept template specification has been completed. Attaching a static statement directly to the template class definition would drag the entire check_concept_impl recursion cycle into the error message.

Therefore, changing the IsContainerCheck property to something like (the rest of the changes are omitted for reading):

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

will result in an error

../constraint.check.hpp: when creating '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 statement failed Eno: Type is not a container model static_assert (is_container :: type :: value, "Type is not a container model");

As you can see, each recursive call to eval_if is corrected in the error description, which is bad because it makes the error message dependent on the number and type of template parameters.

0
source share

All Articles