Suppose I want to use std::conditional
to determine a type, if the type is a vector<...>
the return will be a vector<...>::size_type
and if not it will be int
. (just an example).
A naive way to use std::conditional
:
template<class V> struct is_vector : std::false_type{};
template<class T> struct is_vector<std::vector<T>> : std::true_type{};
template<class C>
using my_size_type = typename std::conditional<
not is_vector<C>::value,
int,
C::size_type // note that this line only makes sense when condition is false
>::type;
However this fails because if C
is say a double
, double::size_type
will give an error, even if the that is the evaluation of the second false option.
So, I am wonder if there is a sort of lazy_conditional
in which the false (or the second false) statement is not evaluated.
I found something here: https://stackoverflow.com/a/5317659/225186 but I don't know how to use it my example.
Note that I know how to get the same result without using std::conditional
:
template<class V> struct my_size_type{typedef int type;};
template<class T> struct my_size_type<std::vector<T>>{typedef std::vector<T>::size_type type;};
The question is if there is a lazy_conditional
that somehow encapsulated a std::conditional
that is short circuited.
After some trial error I manage to use the ideas in https://stackoverflow.com/a/5317659/225186 and get to this that follows. It also makes me think that it is not possible to write std::lazy_conditional
because C::size_type
cannot appear at all in any expression a priori, so two-step expressions are needed.
template<class C, bool B> struct false_case{
typedef void type;
};
template<class C> struct false_case<C, false>{
typedef typename C::size_type type;
};
template<class C>
using size_type = typename std::conditional<
not is_vector<C>::value,
int,
typename false_case<C, not is_vector<C>::value>::type
>::type;
I couldn't even condense this into a macro, because each case is different.
You need a level of indirection.
template<class T> struct identity { using type = T; };
template<class C>
struct size_type_of : identity<typename C::size_type> { };
template<class C>
using size_type = typename std::conditional<not is_vector<C>::value,
identity<int>,
size_type_of<C>>::type::type;
The point is to delay looking at C::size_type
(by instantiating size_type_of<C>
) until you know it has one.
If what you really want to do is "C::size_type
if it exists, int
otherwise", then std::experimental::detected_or_t
is your friend:
template<class C>
using size_type_t = typename C::size_type;
template<class C>
using size_type_or_default = std::experimental::detected_or_t<int, size_type_t, C>;
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