GENERIC solution for replacing if constexpr in C++14

1.2k Views Asked by At

Firstly, I have already seen Constexpr if alternative, but that didn't help.

I updated the post to clarify explicitly the necessity of the generic solution. What I need is a generic solution to use the potential of C++17 if constexpr in C++14. Maybe, we can do something with lambdas and/or boost::hana here?

Below you will find a small example of using if constexpr - I don't need the solution for the below-mentioned case only - rather a generic one, that can be applied in most cases as the replacement of if constexpr if not everywhere. You can assume I am porting C++17 code with if constexpr to C++14 - what is the simplest way of doing that?

I am thinking of solution, which might look like below, but not sure how to implement that: if<condition>(func1).elif<condition2>(func2).else(func3) Other ideas are highly welcome as well.

C++17 code to test:

#include <string>
template<class T>
constexpr bool value = true;

template<>
constexpr bool value<std::string> = false;

template<class T>
void method(const T& arg) {
    if constexpr (value<T>) {
        if (!arg) return;
    }
    //mylogic(arg);
}

int main() {
    std::string arg;
    method(arg);

    int arg2;
    method(arg2);

    return 0;
}
2

There are 2 best solutions below

6
Alan Birtles On

You can just do it the old fashioned way with std::enable_if by moving the type dependent code into a separate function with specialisations:

#include <string>
template<class T>
constexpr bool value = true;

template<>
constexpr bool value<std::string> = false;

template<class T, std::enable_if_t<value<T>, bool> = true>
bool is_unset(const T& arg)
{
    return !arg;
}

template<class T, std::enable_if_t<!value<T>, bool> = true>
bool is_unset(const T& arg)
{
    return false;
}

template<class T>
void method(const T& arg) {
    if (is_unset<T>(arg)) {
        return;
    }
    //mylogic(arg);
}

int main() {
    std::string arg;
    method(arg);

    int arg2;
    method(arg2);

    return 0;
}
1
Marek R On

Here is mcve to start with.

There are couple ways to fix it.

Now since you created value template to do special treatment of std:string it can be achieved by simple overload:

template<class T>
void method(const T& arg) {
    if (!arg) return;
    mylogic(arg);
}

void method(const std::string& arg) {
    mylogic(arg);
}

https://godbolt.org/z/PeWdbadxK

Now assuming that value is something more complex it can go like this:

template<class T>
std::enable_if_t<value<T>> method(const T& arg) {
    if (!arg) return;
    mylogic(arg);
}

template<class T>
std::enable_if_t<!value<T>> method(const T& arg) {
    mylogic(arg);
}

https://godbolt.org/z/Mjvfr7qqb

Apparently you are trying to handle case that T can't be converted to bool, so you can make this this way:

template<class...>
using void_t = void;

template<class T, class U = void>
constexpr bool value = false;

template<class T>
constexpr bool value<T, void_t<decltype(!std::declval<T>())>> = true;

template<typename T>
void mylogic(T&& arg)
{
    std::cout << std::forward<T>(arg) << '\n';
}

template<class T>
std::enable_if_t<value<T>> method(const T& arg) {
    if (!arg) return;
    mylogic(arg);
}

template<class T>
std::enable_if_t<!value<T>> method(const T& arg) {
    mylogic(arg);
}

https://godbolt.org/z/46n87xd6a