我有Conditional
模板
template<bool C, typename ...>
struct Conditional {
};
template<typename C1, typename C2>
struct Conditional<true, C1, C2> {
typedef C1 value;
};
template<typename C1, typename C2>
struct Conditional<false, C1, C2> {
typedef C2 value;
};
似乎可以按预期工作:
<Conditional<(0 != 1), Int<0>, Int<1>>::value; // Int<0>
<Conditional<(0 == 1), Int<0>, Int<1>>::value, // Int<1>
但是它会在返回之前评估所有值:
template<typename G, typename M>
struct DoMove {
private:
constexpr static bool _isRLMove = (M::direction == Direction::LEFT || M::direction == Direction::RIGHT);
public:
using result = typename Conditional<
_isRLMove, typename DoMoveRL<G, M>::result, typename DoMoveUD<G, M>::result>::value;
// ^ when _isRLMove == false evaluates this
};
这会导致DoMoveRL
中的编译错误。
如何根据情况进行评估?我在这里想念什么?
答案 0 :(得分:6)
DoMoveRL<G, M>::result
强制实例化DoMoveRL<G, M>
。
您可能会延迟result
的检索以避免强制实例化:
template<typename G, typename M>
struct DoMove {
private:
constexpr static bool _isRLMove = (M::direction == Direction::LEFT
|| M::direction == Direction::RIGHT);
public:
using result = typename Conditional<
_isRLMove, DoMoveRL<G, M>, DoMoveUD<G, M>>::value::result;
};
答案 1 :(得分:1)
有几种方法可以解决此问题。传统上,添加一个间接层(live example):
template<bool C, template<typename ...> class...>
struct Conditional {
};
template<template<typename...> class C1, template<typename...> class C2>
struct Conditional<true, C1, C2> {
template<typename... Ts>
using apply = C1<Ts...>;
};
template<template<typename...> class C1, template<typename...> class C2>
struct Conditional<false, C1, C2> {
template<typename... Ts>
using apply = C2<Ts...>;
};
using result = typename Conditional<_isRLMove, DoMoveRL, DoMoveUD>::template apply<G, M>::result;
如果实例化模板本身很好并且仅访问result
中断,则可以稍微简化一下。我已经考虑了模板本身的破坏。
在C ++ 17中,如果您更喜欢live example,则可以使用if constexpr
:
template<typename T> struct type_val { using type = T; };
static auto choose_type() {
if constexpr (_isRLMove) {
return type_val<typename DoMoveRL<G, M>::result>{};
} else {
return type_val<typename DoMoveUD<G, M>::result>{};
}
}
using result = typename decltype(choose_type())::type;