Miałem trochę czasu (i dobrego likieru, żeby się z tym zgodzić), aby pomyśleć więcej o problemie. To właśnie wymyśliłem:
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;
}
};
i użytkowania:
check_concept<IsContainerCheck, std::vector<int>, std::vector<int>, float, int>::apply();
Rozwiązaniem nie jest prawdopodobnie najbardziej elegancki jeden ale utrzymuje wiadomość wymuszenia skrócie:
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");
Assert jest wydawane w metodzie constexpr po specjalizacji szablonu check_concept. Osadzenie statycznego asertu bezpośrednio w definicji klasy szablonu przeciągnęłoby cały stos rekurencji check_concept_impl do komunikatu o błędzie.
więc zmieniając cechę IsContainerCheck coś jak (reszta zmian pominięte dla czytelności):
template<typename ContainerType>
struct IsContainerCheck
{
static_assert(is_container<ContainerType>::type::value, "Type is not a container model");
};
przyniesie błąd
../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");
Jak widać każde wywołanie rekurencyjne eval_if jest emended w opisie błędu, który jest zły, ponieważ powoduje, że komunikat o błędzie zależy od ilości i typu parametrów szablonu.
Spodziewam się, że sprawdzanie nastąpi zaraz po utworzeniu szablonu, co niekoniecznie wymaga skonstruowania dowolnego obiektu. – aschepler
Całkiem tak. Po prostu edytowane, aby spróbować to wyrazić. –
Po prostu podrapię to paragrafy.Myślałem, że mam gotcha, który wymagał wywołania konstruktora na opakowaniu, ale nie mogę tego zrobić prostym, więc jest on związany z czymś nie tak z moim kodem. –