2015-07-09 11 views
5

Il codice di seguito viene illustrato il mio problemaproblema C++ Template Metaprogrammazione nella selezione del tipo di

#include <type_traits> 
#include <limits> 
#include <cstdint> 
#include <boost/mpl/if.hpp> 
#include <boost/mpl/eval_if.hpp> 
#include <boost/mpl/identity.hpp> 

///////////////////////////////////////////////////////////////// 
// safe_signed_range 

template < 
    std::intmax_t MIN, 
    std::intmax_t MAX 
> 
struct safe_signed_range { 
}; 

///////////////////////////////////////////////////////////////// 
// safe_unsigned_range 

template < 
    std::uintmax_t MIN, 
    std::uintmax_t MAX 
> 
struct safe_unsigned_range { 
}; 

template<class T, class U> 
using calculate_max_t = typename boost::mpl::if_c< 
    std::numeric_limits<T>::is_signed 
    || std::numeric_limits<U>::is_signed, 
    std::intmax_t, 
    std::uintmax_t 
>::type; 

template<typename T, typename U> 
struct test { 

    typedef calculate_max_t<T, U> max_t; 
    static_assert(std::is_same<max_t, std::intmax_t>::value, "unexpected value for max_t"); 
    static_assert(std::is_signed<max_t>::value, "check parameter"); 

/* 
    typedef typename boost::mpl::if_c< 
     std::is_signed<max_t>::value, 
     safe_signed_range<std::numeric_limits<max_t>::min(), std::numeric_limits<max_t>::max()>, 
     safe_unsigned_range<std::numeric_limits<max_t>::min(), std::numeric_limits<max_t>::max()> 
    >::type type; 
*/ 

    typedef typename boost::mpl::eval_if_c< 
     std::is_signed<max_t>::value, 
     boost::mpl::identity<safe_signed_range<std::numeric_limits<max_t>::min(), std::numeric_limits<max_t>::max()> >, 
     // error shows up here 
boost::mpl::identity<safe_unsigned_range<std::numeric_limits<max_t>::min(), std::numeric_limits<max_t>::max()> > 
    >::type type; 
}; 

test<int, int> t1; 
//test<int, unsigned> t2; 
//test<unsigned, int> t3; 
//test<unsigned, unsigned> t4; 

int main(){ 
    return 0; 
} 

errore si presenta con Clang compilatore come

/Users/robertramey/WorkingProjects/safe_numerics/test/test_z.cpp:116:50: Non-type template argument evaluates to -9223372036854775808, which cannot be narrowed to type 'std::uintmax_t' (aka 'unsigned long')

Questo sembra gradire Boost Mpl isn selezionando il tipo corretto. Per prima cosa ho sospettato (e in realtà sospetto ancora) che tutti gli argomenti relativi a if venissero espansi, quindi ho deciso di utilizzare eval_if, ma ho comunque riscontrato il problema. Ho incluso static_assert per controllare i parametri e posso farlo fallire con il più semplice dei test, anche se fallisce su tutte le combinazioni. Se qualcuno può spiegare il mio errore a me, sarei grato.

risposta

6

Il problema è che si crea un'istanza di un modello (indipendentemente da boost::mpl::identity) non valido per il tipo corrente di safe_unsigned_range. La soluzione a questo è differire l'istanza del modello basata sul predicato booleano passato a boost::mpl::eval_if_c.

Per fare questo dobbiamo prima dobbiamo scrivere la nostra versione di identity per entrambi i tipi gamma:

template<typename Integer, Integer Top, Integer Bottom> 
struct defer_unsigned_lazily { 
    using type = safe_unsigned_range<Top, Bottom>; 
}; 

template<typename Integer, Integer Top, Integer Bottom> 
struct defer_signed_lazily { 
    using type = safe_signed_range<Top, Bottom>; 
}; 

Il modo in cui funziona è che l'istanza non accadrà fino a quando facciamo typename X::type essenzialmente ci dà la semantica pigri come boost::mpl::identity.

Poi abbiamo cambiare il typedef in questo modo:

using limits = std::numeric_limits<max_t>; 
typedef typename boost::mpl::eval_if_c< 
    std::is_signed<max_t>::value, 
    defer_signed_lazily<max_t, limits::min(), limits::max()>, 
    defer_unsigned_lazily<max_t, limits::min(), limits::max()> 
>::type type; 

Dopo di che si dovrebbe compilare come previsto sia Clang e GCC.

Demo

+0

OK - questo ha funzionato - buon lavoro e grazie mille. Naturalmente questa era la mia motivazione per usare la mpl: identità che alla mia mente dovrebbe fare la stessa cosa. Vedrò questo. Grazie ancora. –

Problemi correlati