2017-04-24 1 views
4

Je voudrais utiliser constexpr if pour effectuer une branche au moment de la compilation, mais il ne semble pas être pris en charge par le dernier compilateur MSVC. Y at-il une alternative à ce qui suit ?:Constexpr si alternative

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

En bref: Puis-je simuler constexpr if quand il est pas pris en charge par le compilateur?

+3

Il est un C++ 17 caractéristique – max66

+1

Oui, je sais, le problème est le plus récent MSVC ne supporte pas complètement C++ 17. –

+1

Peut-être intéressant: [simulate-static_if-with-c11c14] (https://baptiste-wicht.com/posts/2015/07/simulate-static_if-with-c11c14.html) – Jarod42

Répondre

5

L'une des 17 voies de pré-C est d'utiliser des spécialisations de modèle partiel, comme ici:

template <template T, bool AorB> 
struct dummy; 

template <typename T, true> 
struct dummy { 
    void MyFunc() { FunctionA<T>(); } 
} 

template <typename T, false> 
struct dummy { 
    void MyFunc() { FunctionB<T>(); } 
} 

template <typename T> 
void Facade() { 
    dummy<T, MeetsConditions<T>::value>::MyFunc(); 
} 

Si vous besoin de plus, que 2 spécialisations - vous pouvez utiliser enum ou valeur intégrale, et faire des spécialisations pour tous les enums nécessaires.

Une autre façon est d'utiliser 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>(); 
} 
4

Vous pouvez le faire l'ancienne, essayé et testé manière d'expédition de tag:

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>{}); 
} 
3

if constexpr est une caractéristique 17 C++; avant le 17 C++, à partir de 11 C++, vous pouvez utiliser SFINAE avec 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 -

Si vous ne pouvez utiliser un compilateur C++ 98, mettre en œuvre un type traits qui fonctionnent comme std::enable_if est vraiment simple; voir l'exemple suivant

template <bool, typename = void> 
struct enableIf 
{ }; 

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

et les fonctions deviennent

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>(); } 
+0

SFINAE ne nécessite pas C++ 11, il était toujours là en C++. – Angew

+0

@Angew - votre droite: est 'std :: enable_if' qui est disponible à partir de C++ 11, pas SFINAE; Merci; réponse modifiée – max66

+0

Il y a toujours 'boost :: enable_if' si C++ 11 n'est pas une option. – Angew

6

Il existe plusieurs alternatives en effet (qui ont été utilisés bien avant if constexpr a commencé à exister).

est un tag expédition:

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

Un autre sont des traits:

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>(); 
} 
4

Si vous utilisez C++ 14 et Boost, envisagez d'utiliser Hana. Mis en œuvre en utilisant Hana, cela ressemble quelque chose comme ceci:

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

Pour le cas spécifique de détection SFINAE et d'exécuter quelque chose que dans ce cas, qui pourrait être aussi simple que:

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