Constexpr if alternative

I would like to use constexpr if for branching at compile time, but it does not seem to be supported by the latest MSVC compiler. Is there an alternative to the following ?:

 template<typename T> void MyFunc() { if constexpr(MeetsConditions<T>::value) { FunctionA<T>(); } else { FunctionB<T>(); } } 

In short: can I mimic constexpr if if it is not supported by the compiler?

+11
source share
5 answers

One way before C ++ 17 is to use partial template specializations, as here:

 template <template T, bool AorB> struct dummy; template <typename T, true> struct dummy { static void MyFunc() { FunctionA<T>(); } } template <typename T, false> struct dummy { static void MyFunc() { FunctionB<T>(); } } template <typename T> void Facade() { dummy<T, MeetsConditions<T>::value>::MyFunc(); } 

If you need more than two specializations, you can use an enumeration or an integer value and create specializations for all necessary enumerations.

Another way is to use std :: enable_if:

 template <typename T> std::enable_if<MeetsConditions<T>::value, void>::type MyFunc() { FunctionA<T>(); } template <typename T> std::enable_if<!MeetsConditions<T>::value, void>::type MyFunc() { FunctionB<T>(); } 
+7
source

There are actually several alternatives (which were used long before the start of if constexpr ).

One of them sends tags:

 template <class T> void Function(std::true_type) { FunctionA<T>(); } template <class T> void Function(std::false_type) { FunctionB<T>(); } template <class T> void MyFunc() { Function<T>(std::integral_constant<bool, MeetsCondition<T>::value>{}); } 

Another feature:

 template <bool B> struct FunctionTraits; template <> struct FunctionTraits<true> { template <class T> static void Call() { FunctionA<T>(); } }; template <> struct FunctionTraits<false> { template <class T> static void Call() { FunctionB<T>(); } }; template <class T> void MyFunc() { FunctionTraits<MeetsCondition<T>::value>::Call<T>(); } 
+7
source

You can do this in an old fashioned, tried and tested way to send tags:

 template<typename T> void MyFuncImpl(std::true_type) { FunctionA<T>(); } template<typename T> void MyFuncImpl(std::false_type) { FunctionB<T>(); } template<typename T> void MyFunc() { MyFuncImpl<T>(std::integral_constant<bool, MeetsConditions<T>::value>{}); } 
+6
source

If you are using C ++ 14 and Boost, consider using Hana . Implemented using Hana, it looks something like this:

 template<typename T> void MyFunc() { hana::eval_if(MeetsConditions<T>::value, [](auto) { FunctionA<T>(); }, [](auto _) { FunctionB<T>(_(exprThatWouldOtherwiseBeAnError)); } ); } 

For a specific case of detecting SFINAE and doing something only in this case, it could be so simple:

 template<typename T> void MyFunc() { auto maybeDoFunctionA = hana::sfinae([]() -> decltype((void) FunctionA<T>()) { FunctionA<T>(); }); } 
+6
source

if constexpr is a C ++ 17 function; before C ++ 17, starting with C ++ 11, you can use SFINAE with std::enable_if

 template<typename T> typename std::enable_if<true == MeetsConditions<T>::value>::type MyFunc () { FunctionA<T>(); } template<typename T> typename std::enable_if<false == MeetsConditions<T>::value>::type MyFunc () { FunctionB<T>(); } 

- EDIT -

If you can only use the C ++ 98 compiler, implementing type traits that work like std::enable_if is very simple; see the following example

 template <bool, typename = void> struct enableIf { }; template <typename T> struct enableIf<true, T> { typedef T type; }; 

and functions become

 template<typename T> typename enableIf<true == MeetsConditions<T>::value>::type MyFunc () { FunctionA<T>(); } template<typename T> typename enableIf<false == MeetsConditions<T>::value>::type MyFunc () { FunctionB<T>(); } 
+4
source

Source: https://habr.com/ru/post/1267094/


All Articles