是否可以构建一个惰性条件元函数

alf*_*lfC 7 c++ conditional templates short-circuiting c++11

假设我想用来std::conditional确定一个类型,如果类型是一个vector<...>返回将是a vector<...>::size_type,如果不是,它将是int.(只是一个例子).

一种天真的使用方式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;
Run Code Online (Sandbox Code Playgroud)

但是这会失败,因为如果C是a double,double::size_type则会给出错误,即使那是第二个错误选项的评估.

所以,我很想知道是否存在一种lazy_conditional未评估错误(或第二个错误)语句的情况.

我在这里找到了一些东西:https://stackoverflow.com/a/5317659/225186但我不知道如何使用它我的例子.


请注意,我知道如何在不使用的情况下获得相同的结果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;};
Run Code Online (Sandbox Code Playgroud)

问题是,是否存在lazy_conditional以某种方式封装了一个std::conditional被短路的东西.


在一些试验错误之后,我设法使用/sf/answers/372236161/中的想法并进行以下操作.它也让我觉得不可能写,std::lazy_conditional因为C::size_type在任何表达式中都不会出现先验,所以需要两步表达式.

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;
Run Code Online (Sandbox Code Playgroud)

我甚至无法将其浓缩成一个宏,因为每个案例都不同.

T.C*_*.C. 5

您需要一个间接级别。

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;
Run Code Online (Sandbox Code Playgroud)

关键是延迟查看C::size_type(通过实例化size_type_of<C>),直到您知道它有一个。


如果你真正想做的是“C::size_type如果它存在,int否则”,那么std::experimental::detected_or_t你的朋友是:

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>;
Run Code Online (Sandbox Code Playgroud)