I need a template expression that selects the first argument type if the first argument is defined, else the second argument type.
select<int, float>::type // type evaluates to int
select<an_undefined_type, float>::type // type evaluates to float
... and the solution has to work with C++03 and Boost 1.33.1 :(
My goal is to accept both int and boost::optional<int> as a function template parameter T, so I can do something like:
template<typename T>
void fn(T& t)
{
int x = std::numeric_limits<select<T::value_type, T>::type>::digits;
}
since boost::optional<int>::value_type is defined.
C++11 solutions are also appreciated.
I don't see a way to do this with template specialization, since I'm trying to specialize not on types but on concepts. Basically, I would need one specialization that matches the any_integer concept and one specialization that matches the boost::optional<any_integer> concept.
I guess with C++11 I could accomplish this specific goal with:
std::conditional<std::is_integral<T>::value, T, T::value_type>::value
but I don't have C++11, and I want the more general solution.
I don't think you can achieve the exact notation you are looking for. However, I think you can use a slightly different notation to achieve what you are semantically after. The problem with your current notation
int x = std::numeric_limits<select<T::value_type, T>::type>::digits;
is that select<T0, T1> expects two types, i.e., the requirement for the types to be present isn't on the select<T0, T1> template but on the function calling it. The way I would change this is to use
int x = std::numeric_limits<select<typename get_value_type<T>::type, T>::type>::digits;
Now all what needs to happen is to have a get_value_type<T> which yields the nested type if present and some type select<T0, T1> is going to ignore if arrives there, e.g., void (or a custom marker type). The get_value_type<T> template should be fairly simple (I saw Dirk Holsopple's answer but I couldn't get it work):
template <typename T>
struct has_value_type
{
typedef char (&true_type)[1];
typedef char (&false_type)[2];
template <typename D> static true_type test(typename D::value_type*);
template <typename D> static false_type test(...);
enum { value = sizeof(test<T>(0)) == 1 };
};
template <typename T, bool = has_value_type<T>::value >
struct get_value_type
{
typedef T type; // EDIT
};
template <typename T>
struct get_value_type<T, true>
{
typedef typename T::value_type type;
};
Obviously, you might want to define your type-traits slightly different so you can use something like
int x = std::numeric_limits<typename get_type<T>::type>::digits;
This would return the nested type if there is a value_type and a type T otherwise.
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