如何实现IF-ELSE条件模板



我有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的编译错误。

一个人如何根据条件进行评估?我在这里缺少什么?

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;
};

有几种方法可以解决这个问题。传统上,添加间接层(实时示例(:

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中,如果您喜欢这样的话,可以使用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;

最新更新