Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement If-Else Conditional template?

I have Conditional template

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

Which seems to work as expected:

<Conditional<(0 != 1), Int<0>, Int<1>>::value; // Int<0>
<Conditional<(0 == 1), Int<0>, Int<1>>::value, // Int<1>

But it evaluates all values before returning:

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

Which causes compile errors from DoMoveRL.

How can one evaluate according to condition? What am I missing here?

like image 276
Dennis Vash Avatar asked Jun 27 '19 08:06

Dennis Vash


People also ask

Can we use else if in Angular?

As we all programmers know if or if else condition is used to create conditional statements so in angular template we can also use the if else but for elseif there is no direct way but we can use alternate way.

What is Ng container and ng-template?

ng-container serves as a container for elements which can also accept structural directives but is not rendered to the DOM, while ng-template allows you to create template content that is not rendered until you specifically (conditionally or directly) add it to the DOM.


2 Answers

DoMoveRL<G, M>::result forces instantiation of DoMoveRL<G, M>.

You might delay the retrieval of result to avoid to force instantiation:

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;
};
like image 200
Jarod42 Avatar answered Nov 15 '22 14:11

Jarod42


There are a couple ways you could go about this. Traditionally, add a layer of indirection (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;

You can simplify this a bit if instantiating the templates themselves is fine and only accessing result breaks. I've accounted for the templates themselves breaking.

In C++17, you can use if constexpr if you like that better (live example):

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;
like image 36
chris Avatar answered Nov 15 '22 13:11

chris