Is it possible to build a lazy conditional metafunction

Suppose I want to use std::conditional to determine the type if the type is vector<...> , return will be vector<...>::size_type , and if it will not be int . (just an example).

The 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 says a double , double::size_type will give an error, even if it is an evaluation of the second false option.

So, I am wondering if there is something like lazy_conditional in which an invalid (or second false) statement is not evaluated.

I found something here: https://stackoverflow.com/a/166269/2326/2126 , but I don't know how to use it in 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, is there a lazy_conditional that somehow encapsulated a std::conditional that is shorted.


After some trial error, I manage to use the ideas in https://stackoverflow.com/a/169479/ and go to the next one. It also makes me think that writing std::lazy_conditional impossible, because C::size_type cannot appear in any expression a priori at all, so two-stage 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 could not even condense this into a macro, because each case is different.

+6
source share
1 answer

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 bottom line is to delay viewing C::size_type (by creating an instance of size_type_of<C> ) until you know what it is.


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>; 
+4
source

Source: https://habr.com/ru/post/1238216/


All Articles