Boost recursive variant along with template c++ - c++11

I am trying to understand boost recursive variant and template. For the below code, I get compilation error of
cannot convert argument 1 from 'std::vector<std::string,std::allocator<_Ty>>' to 'const Boost::variant<boost::detail::variant::recursive_flag<T0>,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19> &'
Error seems to be originating from GetVarValue() function
As per my undertanding I can have a class with _default : which can be vector of int, string, bool, double, vector of int/string/bool/double right?
typedef boost::make_recursive_variant<
int,
std::string,
bool,
double,
std::vector<boost::recursive_variant_> >::type TokenValueType;
template<class T>
class VectorToken : public Token
{
private:
string _name;
vector<T> _default;
public:
VectorToken(string name, vector<T> defaultVal)
: _name(name)
{
_default = defaultVal;
}
virtual TokenValueType GetVarValue()
{
return _default; <-- _default (vector<string>) doesn't like TokenValueType ?
}
};
main()
{
vector<string> tempvec = {"ABC", "LMN", "PQR"};
VectorToken<string> t4 = VectorToken<string>::VectorToken("VECTORSTR", tempvec);
}
The error goes away when I write main like this:
main()
{
vector<TokenValueType> tempvec = { string("ABC"), string("LMN"), string("PQR") };
VectorToken<TokenValueType> t4 = VectorToken<TokenValueType>::VectorToken("VECTORSTR", tempvec);
}

I will simplify that type:
typedef boost::make_recursive_variant<
int,
std::string,
std::vector<boost::recursive_variant_> >::type TokenValueType;
This should be enough to explain it.
TokenValueType is not a variant over (vector of int, vector of string, vector of vector of TokenValueType).
It is a vector over (int or string or TokenValueType).
Here is a MCVE with your syntax errors corrected and one line changed:
return std::vector<TokenValueType>(_default.begin(), _default.end());

Related

Filling N sized array with constexpr c++11

I'm aware that my code should work in c++14 but I have to replicate this behaviour in c++11, I havent been able to make a equivalent init() could anyone help?
enum MyEnum {
BANANA, APPLE, PINEAPPLE, ORANGE, FRUIT_AMOUNT
};
template<MyEnum>
struct Fruit{
virtual ~Fruit(){}
virtual void dostuff(){}
};
template <>
struct Fruit<ORANGE>{
void dostuff(){ cout<<"Hey apple!"<<endl;
}
constexpr array< Fruit*, FRUIT_AMOUNT > init(){
array< Fruit*, FRUIT_AMOUNT > myArray;
for(int i =0; i < FRUIT_AMOUNT; i++)
myArray[i] = new Fruit< (MyEnum) i >();
return myArray;
}
array<Fruit*, FRUIT_AMOUNT> myPrettyFruits = init();
I'm aware that my code should work in c++14
Ehmm... not at all.
Your code has a lot of problems.
Some of them, in no particular order
(1) You can't write
array<Fruit*, FRUIT_AMOUNT>
because Fruit isn't a type; it's a template class.
So, by example, Fruit<BANANA> is a type, and you can write
std::array<Fruit<BANANA> *, FRUIT_AMOUNT>
but you can't have a pointer to Fruit because Fruit (without explicating a template argument) isn't a type.
A possible solution for this problem is make all Fruit types inheriting from a common base; by example
struct FruitBase
{ };
template <MyEnum>
struct Fruit : public FruitBase
{
virtual ~Fruit () {}
virtual void dostuff () {}
};
This way you can have an array of FruitBase pointers
std::array<FruitBase *, FRUIT_AMOUNT>
So you can put in the array pointer to Fruit<Something> types that are also FruitBase pointers.
(2) You can't have
Fruit< (MyEnum) i >
where i is a run-time known variable, because a template argument must be known compile time.
A possible C++14 solution is use std::make_index_sequence to get a sequence of template (so compile-time known) std::size_t values.
I suggest something as follows
template <std::size_t ... Is>
constexpr std::array<FruitBase *, FRUIT_AMOUNT>
init_helper (std::index_sequence<Is...> const &)
{ return { { (FruitBase*)(new Fruit<(MyEnum)Is>()) ... } }; }
constexpr std::array<FruitBase *, FRUIT_AMOUNT> init ()
{ return init_helper(std::make_index_sequence<FRUIT_AMOUNT>{}); }
Observe that both functions are a single return statement; and this is necessary for a constexpr C++11 function.
Unfortunately std::index_sequence and std::make_index_sequence are available only starting from C++14. But it's possible make a C++11 substitute for they.
(3) new Something{} can't be executed compile-time
So you can define init_helper() constexpr but it's a fake constexpr function (so also init() is a fake constexpr function) because can't be executed compile time.
So you can write
std::array<FruitBase *, FRUIT_AMOUNT> myPrettyFruits = init();
but myPrettyFruits is initialized run-time.
If you try to initialize it compile-time
constexpr std::array<FruitBase *, FRUIT_AMOUNT> myPrettyFruits = init();
you get a compilation error.
The following is a full compiling C++11 example, with a std::index_sequence/std::make_index_sequence replacement, that works only run-time
#include <array>
#include <iostream>
template <std::size_t...>
struct indexSequence
{ using type = indexSequence; };
template <typename, typename>
struct concatSequences;
template <std::size_t... S1, std::size_t... S2>
struct concatSequences<indexSequence<S1...>, indexSequence<S2...>>
: public indexSequence<S1..., ( sizeof...(S1) + S2 )...>
{ };
template <std::size_t N>
struct makeIndexSequenceH
: public concatSequences<
typename makeIndexSequenceH<(N>>1)>::type,
typename makeIndexSequenceH<N-(N>>1)>::type>::type
{ };
template<>
struct makeIndexSequenceH<0> : public indexSequence<>
{ };
template<>
struct makeIndexSequenceH<1> : public indexSequence<0>
{ };
template <std::size_t N>
using makeIndexSequence = typename makeIndexSequenceH<N>::type;
enum MyEnum
{ BANANA, APPLE, PINEAPPLE, ORANGE, FRUIT_AMOUNT };
struct FruitBase
{ };
template <MyEnum>
struct Fruit : public FruitBase
{
virtual ~Fruit () {}
virtual void dostuff () {}
};
template <>
struct Fruit<ORANGE> : public FruitBase
{ void dostuff () { std::cout << "Hey apple!" << std::endl; } };
// fake constexpr function: new can't be executed compile-time
template <std::size_t ... Is>
constexpr std::array<FruitBase *, FRUIT_AMOUNT>
init_helper (indexSequence<Is...> const &)
{ return { { (FruitBase*)(new Fruit<(MyEnum)Is>()) ... } }; }
// fake constexpr: init_helper() can't be executed compile-time
constexpr std::array<FruitBase *, FRUIT_AMOUNT> init ()
{ return init_helper(makeIndexSequence<FRUIT_AMOUNT>{}); }
int main ()
{
// compile (executed run-time)
std::array<FruitBase *, FRUIT_AMOUNT> myPrettyFruits = init();
// compilation error (init() can't be executed compile-time)
//constexpr std::array<FruitBase *, FRUIT_AMOUNT> myPrettyFruits = init();
}

Return type mismatch for operator implementation in unordered_map wrapper

I am implementing a simple wrapper on top of std::unordered_map with user-defined hash functions and simple iterator/const_iterator. Most of the parts are working but I am stuck with * and -> operator implementations. The mapping from returns types of unordered_map operators to my wrapper operators are hitting compilation error due to type-mismatch errors.
Basically, both "return internalItr" and "return &(*internalItr)" are hitting type-mismatch. However, for testing sake (commented code), I used a const member variable in the const_iterator class, but then the assignment "return_type = *internalItr" works, which is basically the same type-conversion. But keeping a const member variable in const_iterator is not a solution for me as it will hit other issues due to const-ness in "it=h.begin()". I cannot change any public api signatures due to legacy library code and my options are limited. I am sorry for posting this long code chunk but couldn't find a better way to illustrate my scenario of a std::unordered_map with 3 template parameters. However, I have omitted the non-interesting/working template implementation codes for the sake of brevity, but included all the api's to provide the background.
Your comments are appreciated!
template< class Key >
class HashFunction
{
public:
HashFunction(){};
HashFunction( const Key & inKey );
inline operator unsigned() const
{
return hashCode;
}
size_t operator()(const Key &inKey) const;
private:
unsigned hashCode;
};
template< class Key, class Val, class Hash = HashFunction< Key > >
class unordered_map_wrapper
{
private:
typedef typename unordered_map<Key,Val,Hash>::const_iterator int_const_iterator;
typedef typename unordered_map<Key,Val,Hash>::iterator int_iterator;
public:
typedef std::pair< Key, Val > key_value;
class iterator
{
friend class unordered_map_wrapper;
private:
iterator( int_iterator & inIterator );
public:
iterator();
private:
int_iterator internalItr;
};
class const_iterator
{
friend class unordered_map_wrapper;
private:
const_iterator( const int_const_iterator & inIterator );
public:
const_iterator();
const key_value & operator*() const;
const key_value * operator->() const;
const_iterator & operator++();
bool operator!=( const const_iterator & inIterator ) const;
private:
int_const_iterator internalItr;
//const key_value return_type;
};
const_iterator begin() const
{
return const_iterator( mTable->begin() );
}
const_iterator end() const
{
return const_iterator( mTable->end() );
}
unordered_map_wrapper();
std::pair< iterator, bool > insert(const key_value & inPair);
private:
unordered_map<Key, Val, Hash> * mTable;
};
template< class Key, class Val, class Hash >
unordered_map_wrapper< Key, Val, Hash >::const_iterator::const_iterator()
{
}
template< class Key, class Val, class Hash >
unordered_map_wrapper< Key, Val, Hash >::const_iterator::const_iterator( const int_const_iterator & inIterator ) :
internalItr( inIterator )
{
}
template< class Key, class Val, class Hash >
unordered_map_wrapper< Key, Val, Hash >::unordered_map_wrapper()
{
mTable=new unordered_map<Key, Val, Hash>(10);
}
template< class Key, class Val, class Hash >
const typename unordered_map_wrapper< Key, Val, Hash >::key_value & unordered_map_wrapper< Key, Val, Hash >::const_iterator::operator*() const
{
return *internalItr;
}
template< class Key, class Val, class Hash >
const typename unordered_map_wrapper< Key, Val, Hash >::key_value * unordered_map_wrapper< Key, Val, Hash >::const_iterator::operator->() const
{
//return internalItr;
return &(*internalItr);
//return_type = *internalItr;
//return &return_type;
}
int main() {
unordered_map_wrapper<string, unsigned> h;
unordered_map_wrapper<string, unsigned>::const_iterator it;
h.insert(std::make_pair<string, unsigned>(string("One"), 1));
std::cout << "MAP VALUES: " << endl;
for ( it = h.begin() ; it != h.end(); ++it )
std::cout << " " << it->first << ":" << it->second << endl;
return 0;
}
Compilation error:
error: cannot convert 'const std::pair<const std::basic_string<char>, unsigned int>*' to 'const key_value* {aka const std::pair<std::basic_string<char>, unsigned int>*}' in return
return &(*internalItr); ^
or
error: cannot convert 'const int_const_iterator {aka const std::__detail::_Node_const_iterator<std::pair<const std::basic_string<char>, unsigned int>, false, true>}' to 'const key_value* {aka const std::pair<std::basic_string<char>, unsigned int>*}' in return
return internalItr;
^
I could get around the above above issue by:
typedef std::pair< const Key, Val > key_value;
But now hitting some other issue. Whenever I add another nonconst-overloaded begin() fn it fails. Why is this not able to pick the correct begin() based on the const-ness which works with a typical STL container?
iterator begin()
{
return iterator( mTable->begin());
}
The error message is:
prog.cpp:159:22: error: no match for ‘operator=’ (operand types are ‘unordered_map_wrapper<std::__cxx11::basic_string<char>, unsigned int>::const_iterator’ and ‘unordered_map_wrapper<std::__cxx11::basic_string<char>, unsigned int>::iterator’)
for ( it = h.begin() ; it != h.end(); ++it )
prog.cpp:75:13: error: invalid initialization of non-const reference of type
‘unordered_map_wrapper<std::__cxx11::basic_string<char>, unsigned
int>::int_iterator& {aka std::__detail::_Node_iterator<std::pair<const
std::__cxx11::basic_string<char>, unsigned int>, false, true>&}’ from an
rvalue of type ‘std::unordered_map<std::__cxx11::basic_string<char>,
unsigned int, HashFunction<std::__cxx11::basic_string<char> >,
std::equal_to<std::__cxx11::basic_string<char> >,
std::allocator<std::pair<const std::__cxx11::basic_string<char>, unsigned
int> > >::iterator {aka std::__detail::_Node_iterator<std::pair<const
std::__cxx11::basic_string<char>, unsigned int>, false, true>}’
return iterator( mTable->begin());
^~~~~~~~~~~~~~~~~~~~~~~~~~

C++ template deduction couldn't infer template argument

I have the following scenario:
struct AP;
struct B
{
B() : m(2) {}
int m;
};
struct A : private B
{
A() : B(), n(1) {}
private:
int n;
friend AP;
};
struct AP
{
AP(A& a) : a_(a) {}
template<typename T>
struct A_B {
using type = typename std::enable_if< std::is_base_of< typename std::remove_reference<T>::type,
A >::value,
T >::type;
};
template<typename T>
operator typename A_B<T>::type()
{
return static_cast<T>(a_);
}
template<typename T>
typename A_B<T>::type get()
{
return static_cast<T>(a_);
}
int& n() { return a_.n; }
private:
A& a_;
};
int main()
{
A a;
AP ap(a);
ap.n() = 7;
const B& b = ap.get<const B&>();
//const B& b = ap; candidate template ignored: couldn't infer template argument 'T'
//auto b = static_cast<const B&>(ap); candidate template ignored: couldn't infer template argument 'T'
std::cout<<b.m;
}
The commented lines wouldn't compile. Clang++ notes that "candidate template ignored: couldn't infer template argument 'T'"
Why am I not able to get a reference to A's base with the cast operator?
I think the code would look much nicer that way.
The answer that you posted works, but is overkill unless you really want a static_assert message.
Classic templating works just fine in this instance because A is already convertible to B:
struct AP
{
AP(A& a) : a_(a) {}
template<typename T>
operator T()
{
return a_;
}
template<typename T>
T get()
{
return a_;
}
int& n() { return a_.n; }
private:
A& a_;
};
Demo
I found the answer here: http://www.mersenneforum.org/showthread.php?t=18076
This is the key: "when you want the compiler to deduce argument types, those types must not be dependent types"
With this it compiles:
template<typename T>
operator T()
{
static_assert(std::is_base_of< typename std::remove_reference<T>::type,A >::value,
"You may cast AP only to A's base classes.");
return static_cast<T>(a_);
}

boost::iterator_facade operator->() fails to compile

Consider the following code:
#include <boost/iterator/iterator_facade.hpp>
#include <map>
// Class implements an stl compliant iterator to access the "sections" stored within a configuration.
template < typename _Iterator, typename _Reference >
class Section
: public boost::iterator_facade<
Section< _Iterator, _Reference >,
_Iterator,
boost::random_access_traversal_tag,
_Reference
>
{
private:
// Define the type of the base class:
typedef boost::iterator_facade<
Section< _Iterator, _Reference >,
_Iterator,
boost::random_access_traversal_tag,
_Reference
> base_type;
public:
// The following type definitions are common public typedefs:
typedef Section< _Iterator, _Reference > this_type;
typedef typename base_type::difference_type difference_type;
typedef typename base_type::reference reference;
typedef _Iterator iterator_type;
public:
explicit Section( const iterator_type it )
: m_it( it )
{ }
// Copy constructor required to construct a const_iterator from an iterator:
template < typename _U >
Section( const Section< _U, _Reference > it )
: m_it( it.m_it )
{ }
private:
// The following classes are friend of this class to ensure access onto the private member:
friend class boost::iterator_core_access;
template < typename _Iterator, typename _Reference > friend class Section;
void increment( ){ ++m_it; } // Advance by one position.
void decrement( ){ --m_it; } // Retreat by one position.
void advance( const difference_type& n ){ m_it += n }; // Advance by n positions.
bool equal( const this_type& rhs ) const{ return m_it == rhs.m_it; } // Compare for equality with rhs.
reference dereference( ) const { return m_it->second; } // Access the value referred to.
difference_type distance_to( const this_type& rhs ) const{ return rhs.m_it - m_it; } // Measure the distance to rhs.
private:
// Current "section" iterator:
iterator_type m_it;
};
struct Data
{
void f( ) const
{ }
};
typedef std::map< int, Data > map_type;
typedef Section< const map_type::const_iterator, const Data& > iterator_type;
map_type g_map;
iterator_type begin( )
{
return iterator_type( g_map.begin( ) );
}
void main( )
{
iterator_type i = begin( );
// i->f( ); // <--- error C2039: 'f' : is not a member of 'std::_Tree_const_iterator<_Mytree>'
( *i ).f( );
}
So the iterator facade shall return a reference to Data type. This works well when dereference operator is called but compile fails when operator->() is called. So I am a bit confused because operator->() tries to return a std::map::iterator. Any ideas ?
The iterator returns an iterator on dereference. To get the f part, you need to dereference twice.
It looks a lot like you misunderstood the meaning of the template arguments to iterator_facade. The second argument is not supposed to be any iterator type (this is what causes all your trouble). Instead you should use it to name your value_type.¹
From the way you specified the dereference operation (and Ref) and wanted to use it in main (i->f()) it looks like you just wanted to iterate the map's values. So, I'd rewrite the whole thing using more descriptive names as well, and here it is, working:
Live On Coliru
#include <boost/iterator/iterator_facade.hpp>
#include <map>
// Class implements an stl compliant iterator to access the "sections" stored within a configuration.
template <typename Map, typename Value = typename Map::mapped_type>
class MapValueIterator : public boost::iterator_facade<MapValueIterator<Map>, Value, boost::random_access_traversal_tag, Value const&> {
private:
// Define the type of the base class:
typedef Value const& Ref;
typedef boost::iterator_facade<MapValueIterator<Map>, Value, boost::random_access_traversal_tag, Ref> base_type;
public:
// The following type definitions are common public typedefs:
typedef MapValueIterator<Map> this_type;
typedef typename base_type::difference_type difference_type;
typedef typename base_type::reference reference;
typedef typename Map::const_iterator iterator_type;
public:
explicit MapValueIterator(const iterator_type it) : m_it(it) {}
// Copy constructor required to construct a const_iterator from an iterator:
template <typename U, typename V> MapValueIterator(const MapValueIterator<U,V> it) : m_it(it.m_it) {}
private:
// The following classes are friend of this class to ensure access onto the private member:
friend class boost::iterator_core_access;
template <typename U, typename V> friend class MapValueIterator;
void increment() { std::advance(m_it); } // Advance by one position.
void decrement() { std::advance(m_it, -1); } // Retreat by one position.
void advance(const difference_type &n) { std::advance(m_it, n); } // Advance by n positions.
bool equal(const this_type &rhs) const { return m_it == rhs.m_it; } // Compare for equality with rhs.
reference dereference() const { return m_it->second; } // Access the value referred to.
difference_type distance_to(const this_type &rhs) const { return rhs.m_it - m_it; } // Measure the distance to rhs.
private:
// Current iterator:
iterator_type m_it;
};
#include <iostream>
struct Data {
void f() const {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
};
typedef std::map<int, Data> map_type;
template <typename Map>
MapValueIterator<Map> map_value_iterator(Map const& m) {
return MapValueIterator<Map>(m.begin());
}
int main() {
map_type g_map;
auto i = map_value_iterator(g_map);
i->f();
}
Which prints the output
void Data::f() const
as you'd expect.
Note that there are numerous places where I implemented the member functions using standard library facilities. Note as well, the iterator "mimics" random access, but it won't have the expected performance characteristics (increment is O(n)).
Final note: I'd recommend against having the implicit conversion constructor. I think you can do without it.
¹ The reference-type should typically be the same (but ref-qualified) except in rare cases where you actually "proxy" the values. This is an advanced topic and rarely should be used.

Is there a way to print a constexpr string during compiletime?

I'm trying to do the following (only relevant parts of 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 the static_assert allows only literals to be printed. The same is with BOOST_STATIC_ASSERT_MSG macro.
So my question is - is there any way to output a constexpr string during compilation?
If there is a gcc extension providing this functionality that would also be great.
Used compiler gcc 4.8.1
GCC does not provide such a mechanism as you want. However you will not need
it if you are able to refactor your code somewhat as illustrated in the
following program. (I have filled in a few gaps so as to give us a
compilable 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 presume that
true_t is not an alias or equivalent of std::true_type, but rather
just a place-holder for some ResultType that is a container type. As
the test program shows, no such specialization is now necessary, because
IsContainerCheck<ResultType>() will static_assert, or not, depending
on ResultType, in the unspecialized run<ResultType>::apply().
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.

Resources