2013-07-18 7 views
7

che sto cercando di fare le seguenti (solo parti rilevanti del codice qui sotto):C'è un modo per stampare una stringa di constexpr durante compiletime?

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

Questo fallisce perché static_assert consente solo letterali da stampare. Lo stesso è con la macro BOOST_STATIC_ASSERT_MSG.

Quindi la mia domanda è: esiste un modo per generare una stringa di constexpr durante la compilazione? Se c'è un'estensione gcc che fornisce questa funzionalità sarebbe anche ottima.

Usato compilatore gcc 4.8.1

risposta

6

GCC non prevede un tale meccanismo come si desidera. Tuttavia non è necessario lo se si è in grado di ridefinire il codice come illustrato nel programma seguente . (Ho riempito un paio di lacune in modo da darci un esempio compilabile ):

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

Nella tua specializzazione _check_concept::struct run<true_t> Presumo che true_t è non un alias o un equivalente di std::true_type, ma piuttosto solo un segnaposto per un numero ResultType ovvero un tipo di contenitore. Come mostra il programma di test , non è necessaria alcuna specializzazione, perché IsContainerCheck<ResultType>() sarà static_assert, o meno, a seconda di su ResultType, nella versione non specializzata run<ResultType>::apply().

+0

Mi aspetto che il controllo si verifichi non appena il modello viene istanziato, il che non richiede necessariamente che qualsiasi oggetto sia costruito. – aschepler

+0

Proprio così. Appena modificato per provare ed esprimere quello. –

+0

Mi limiterò a graffiare quel paragrafo.Pensavo di avere un trucco che richiedeva una chiamata al costruttore nel wrapper ma non posso renderlo semplice, quindi è legato a qualcosa di sbagliato nel mio codice. –

0

Ho avuto un po 'di tempo (e un buon liquore per venire con esso) per pensare di più sul problema. Questo è ciò che mi si avvicinò con:

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

e l'utilizzo:

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

La soluzione non è probabilmente il più elegante ma mantiene il messaggio di asserzione breve:

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");

L'asserzione viene emessa in un metodo constexpr dopo che è stata eseguita la specializzazione del modello check_concept. Incorporare l'asser statico direttamente nella definizione della classe template trascina l'intero stack di ricorsione check_concept_impl nel messaggio di errore.

Quindi cambiare il tratto IsContainerCheck a qualcosa di simile (resto delle modifiche omesso per leggibilità):

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

sarebbe produrre un errore

../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");

Come si può vedere ogni chiamata eval_if ricorsiva è emendato nella descrizione dell'errore che non funziona perché rende il messaggio di errore dipendente dalla quantità e dal tipo di parametri del modello.

Problemi correlati