2012-09-25 13 views
6

Podczas kompilacji w C++ 11 w funkcji szablonu, która pobiera 2 parametry szablonu, z których oba muszą być typu liczb całkowitych bez znaku, chciałbym mieć zmienną lokalną mieć typ, który z dwóch parametrów szablonu ma więcej bity. W C++ 03 mógłbym napisać coś takiego:C++ 11 sposób na napisanie szablonu do wybrania większej liczby całkowitej?

template<bool, class T, class U> 
struct pick_first; 

template<class T, class U> 
struct pick_first<true, T, U> { 
    typedef T type; 
}; 

template<class T, class U> 
struct pick_first<false, T, U> { 
    typedef U type; 
}; 

template<class T, class U> 
struct pick_bigger { 
    typedef typename pick_first<(sizeof(T) >= sizeof(U)), T, U>::type type; 
}; 

// usage 
template<class uintX_t, class uintY_t> 
void foo() { 
    typename pick_bigger<uintX_t, uintY_t>::type mylocal = 0; 
    // insert doing stuff with mylocal here 
} 

mogę wykorzystać dowolny z nowych funkcji C++ 11, aby to prostsze? Wiem, że mogłem używać szablonów variadic, aby działały z więcej niż parami typów i zamiast używać pick_first, mogłem napisać wiele specjalizacji, aby działały z nowymi typami int_leastX_t i int_fastX_t. Ale jestem ciekawy, czy istnieje po prostu lepsze podejście do tego. Może w jakiś sposób wykorzystując auto/constexpr/decltype?

+4

Czy brałeś pod uwagę 'std :: typ_typowy' –

+0

Nie słyszałem o std :: typ_typowy! Bardzo interesujące. To byłoby dla mnie. Powinieneś jednak opublikować odpowiedź, aby móc Cię głosować;) –

+0

@ DavidRodríguez-dribeas Ale 'typ_typowy' nie zawsze będzie działał ze względu na zasady dotyczące całkowitej liczby promocji. Na przykład 'std :: common_type :: type' to' int', który może być większy niż jeden z dwóch typów. – Praetorian

Odpowiedz

7

Twój pick_first jest tylko std :: warunkowe w C++ 11, więc można napisać

template<class T, class U> 
struct wider { 
    using type = typename std::conditional<sizeof(T) >= sizeof(U), T, U>::type; // I'm using the C++11 type alias feature 1) to educate people about them and 2) because I like them better than typedefs. 
}; 

Jeśli chcesz po prostu typ odpowiedni dla gospodarstwa wynik pewnej ekspresji z udziałem obu typów i nie zrobić koniecznie dokładnie jeden z dwóch typów następnie std::common_type, a może auto, jest najlepszym rozwiązaniem:

template<class uintX_t, class uintY_t> 
void foo() { 
    typename std::common_type<uintX_t, uintY_t>::type mylocal = 0; 
    // insert doing stuff with mylocal here 
} 

// or 
template<class uintX_t, class uintY_t> 
void foo(uintX_t x, uintY_t y) { 
    auto mylocal = x + y; 
} 

a realizacja pick_bigger brakuje typename tam: typedef typename pick_first<(sizeof(T) >= sizeof(U)), T, U>::type type;

+0

To dodaje zawikłaną magię szablonu, z kodem, który nie kompiluje się z najczęściej używanym kompilatorem, w celu wytworzenia suboptymalnego typu dla zmiennej lokalnej, do której OP chce mieć typ. To jest wyjątkowo głupie. Ale wygląda sprytnie. –

+0

Wow, nie był świadomy std :: conditional, sweet. –

+0

@JosephGarvin Możesz spojrzeć na http://en.cppreference.com/w/cpp/types, aby zobaczyć wszystkie nowe cechy typu. – bames53

1

ponieważ oba typy są niepodpisane, po prostu wykonaj decltype(T1() + T2()).

+5

Ma to ten sam problem z integracją całkowitą jak typ_typowy, decltype (char() + short()) to int. Jeśli jest to akceptowalne, najlepszym rozwiązaniem jest użycie parametru common_type. – bames53

+0

@ barnes54: common_type dodaje zależność od nagłówka. nie ma takiej potrzeby. dla uzyskania 'unsigned int' zamiast' short', OP pyta o odpowiedni typ dla zmiennej lokalnej. najbardziej odpowiednim typem jest ten, który może przechowywać wyniki ekspresji bezpośrednio bez konwersji. to właśnie wytwarza to wyrażenie. i że najbardziej odpowiedni typ nie jest tym, co wytwarza głupi, nad-inżynierowany selektor szablonowy. –

+0

@downvoter: wyjaśnij swoje zdanie. Wiem, że wyjaśnienie * będzie brzmiało rozsądnie, tak samo jak potrójnie przegłosowany komentarz barnes53, i prawdopodobnie nie będę nawet komentować tego (już omówiono). ale tylko dla kompletności. –