2015-07-09 11 views
5

Poniższy kod ilustruje mój problemC++ Template METAPROGRAMOWANIE kwestią wyboru typu

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

błąd pokazuje się z brzękiem kompilator jako

/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')

To wygląda jak Boost, MPL ISN wybierz właściwy typ. Najpierw podejrzewałem (i tak naprawdę wciąż podejrzewam), że wszystkie argumenty dotyczące tego, czy są rozszerzane, zmieniłem więc na eval_if, ale nadal mam problem. Zawarłem static_assert, aby sprawdzić parametry i sprawić, by zakończył się niepowodzeniem z najprostszym testem - choć nie przy wszystkich kombinacjach. Jeśli ktokolwiek może mi wyjaśnić mój błąd, byłbym wdzięczny.

Odpowiedz

6

Problem polega na tym, że tworzysz szablon (niezależnie od boost::mpl::identity), który jest nieprawidłowy dla bieżącego typu safe_unsigned_range. Rozwiązaniem tego problemu jest odroczenie tworzenia szablonu na podstawie predykatu boolowskiego przekazanego do boost::mpl::eval_if_c.

Aby to zrobić musimy najpierw napisać własną wersję identity dla obu typów Zakres:

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

Sposób ten działa jest to, że instancji nie nastąpi, dopóki robimy typename X::type zasadniczo dając nam leniwe semantykę jak boost::mpl::identity.

Następnie zmienić typedef tak:

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; 

Następnie należy opracować zgodnie z oczekiwaniami zarówno Clang i GCC.

Demo

+0

OK - zadziałało - dobra robota i wielkie dzięki. Oczywiście była to moja motywacja do korzystania z mpl: tożsamość, która moim zdaniem powinna zrobić to samo. Zajrzę w to. Dzięki jeszcze raz. –

Powiązane problemy