2013-07-18 15 views
7

Próbuję wykonać następujące (tylko odpowiednie fragmenty kodu poniżej):Czy istnieje sposób drukowania ciągów constexpr podczas kompilacji?

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

To nie dlatego, że static_assert pozwala tylko literały mają zostać wydrukowane. To samo dotyczy makra BOOST_STATIC_ASSERT_MSG.

Moje pytanie brzmi - czy istnieje sposób na wyprowadzenie ciągu constexpr podczas kompilacji? Jeśli istnieje rozszerzenie gcc oferujące tę funkcję, która również byłaby świetna.

kompilator gcc 4.8.1 Używane

Odpowiedz

6

GCC nie przewiduje takiego mechanizmu, jak chcesz. Jednak nie będziesz potrzebować go, jeśli będziesz w stanie trochę zmodyfikować kod, jak pokazano w następującym programie . (Mam wypełnione w ciągu kilku luk, tak aby dać nam compilable przykład):

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

W swojej specjalizacji _check_concept::struct run<true_t> Przypuszczam, że true_t jest nie aliasem lub odpowiednik std::true_type, ale raczej tylko uchwyt na miejsce dla niektóre ResultType który jest kontenerem typu. Jak pokazuje program testowy, żadna taka specjalizacja nie jest teraz potrzebna, ponieważ IsContainerCheck<ResultType>() będzie static_assert, lub nie, w zależności od na ResultType, w nieokreślonym run<ResultType>::apply().

+0

Spodziewam się, że sprawdzanie nastąpi zaraz po utworzeniu szablonu, co niekoniecznie wymaga skonstruowania dowolnego obiektu. – aschepler

+0

Całkiem tak. Po prostu edytowane, aby spróbować to wyrazić. –

+0

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. –

0

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.

Powiązane problemy