At compile time in C++11 in a template function that takes 2 template parameters, both of which must be unsigned integer types, I'd like to have a local variable have the type of whichever of the two template parameters has more bits. In C++03 I might write something like:
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
}
Can I leverage any of the new C++11 features to make this simpler? I know I could use variadic templates to make it work with more than just pairs of types, and instead of using pick_first I could write lots of specializations to make it work with the new int_leastX_t and int_fastX_t types. But I'm curious if there's just a plain better approach to this. Maybe somehow leveraging auto/constexpr/decltype?
There are ways to restrict the types you can use inside a template you write by using specific typedefs inside your template. This will ensure that the compilation of the template specialisation for a type that does not include that particular typedef will fail, so you can selectively support/not support certain types.
Class Template Declarationtemplate <class T> class className { private: T var; ... .. ... public: T functionName(T arg); ... .. ... }; In the above declaration, T is the template argument which is a placeholder for the data type used, and class is a keyword.
Class Templates like function templates, class templates are useful when a class defines something that is independent of the data type. Can be useful for classes like LinkedList, BinaryTree, Stack, Queue, Array, etc. Following is a simple example of a template Array class.
This is my solution that can select the widest from N types up to the template recursion limit.
I've also included the code for narrowest.
template <typename TFirst, typename... TOther>
struct widest {
private:
using rhs_recursive_type = typename widest<TOther...>::type;
public:
using type =
typename std::conditional<sizeof(TFirst) >= sizeof(rhs_recursive_type),
TFirst, rhs_recursive_type>::type;
};
template <typename TFirst>
struct widest<TFirst> {
using type = TFirst;
};
template <typename TFirst, typename... TOther>
struct narrowest {
private:
using rhs_recursive_type = typename widest<TOther...>::type;
public:
using type =
typename std::conditional<sizeof(TFirst) <= sizeof(rhs_recursive_type),
TFirst, rhs_recursive_type>::type;
};
template <typename TFirst>
struct narrowest<TFirst> {
using type = TFirst;
};
Your pick_first is just std::conditional in C++11, so you could write
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.
};
If you just want a type suitable for holding the result of some expression involving both types and don't necessarily need exactly one of the two types then std::common_type
, or perhaps auto
, is the best solution:
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;
}
and your implementation of pick_bigger is missing a typename
in there: typedef typename pick_first<(sizeof(T) >= sizeof(U)), T, U>::type type;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With