是否可以构建一个惰性条件元函数
Is it possible to build a lazy conditional metafunction
假设我想使用 std::conditional
来确定类型,如果类型是 vector<...>
,则 return 将是 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;
然而这失败了,因为如果 C
是说 double
,double::size_type
会给出一个错误,即使那是第二个 false 选项的评估。
所以,我想知道是否有一种 lazy_conditional
不评估错误(或第二个错误)陈述。
我在这里找到了一些东西: 但我不知道如何使用我的示例。
请注意,我知道如何在不使用 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;};
问题是是否有一个 lazy_conditional
以某种方式封装了一个短路的 std::conditional
。
经过一些尝试错误后,我设法使用了 中的想法,并得到了接下来的结果。这也让我觉得写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;
我什至无法将其压缩成一个宏,因为每个案例都不一样。
你需要一个间接级别。
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;
重点是延迟查看 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>;
假设我想使用 std::conditional
来确定类型,如果类型是 vector<...>
,则 return 将是 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;
然而这失败了,因为如果 C
是说 double
,double::size_type
会给出一个错误,即使那是第二个 false 选项的评估。
所以,我想知道是否有一种 lazy_conditional
不评估错误(或第二个错误)陈述。
我在这里找到了一些东西: 但我不知道如何使用我的示例。
请注意,我知道如何在不使用 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;};
问题是是否有一个 lazy_conditional
以某种方式封装了一个短路的 std::conditional
。
经过一些尝试错误后,我设法使用了 中的想法,并得到了接下来的结果。这也让我觉得写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;
我什至无法将其压缩成一个宏,因为每个案例都不一样。
你需要一个间接级别。
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;
重点是延迟查看 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>;