2017-04-24 81 views
4

我想在編譯時使用constexpr if進行分支,但它似乎沒有被最新的MSVC編譯器支持。有下列?:Constexpr if

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

總之替代:我可以模擬constexpr if當它不被編譯器支持?

+3

這是一個C++ 17功能 – max66

+1

是的我知道,問題是最新的MSVC不完全支持C++ 17。 –

+1

可能很有意思:[模擬靜態圖片與c11c14](https://baptiste-wicht.com/posts/2015/07/simulate-static_if-with-c11c14.html) – Jarod42

回答

5

一個預C++ 17層的方法是使用局部模板特,喜歡這裏:

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

如果您需要更多,比2個專業化 - 您可以使用枚舉或整數值,併爲所有需要的枚舉進行專門化。

另一種方法是使用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

你可以做到這一點老土,久經考驗的標籤分發方式:

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是一個C++ 17的功能;之前,C++ 17,從C++ 11日起,您可以使用SFINAE與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>(); } 

- 編輯 -

如果您只能使用C++編譯器98,實施像std::enable_if那樣工作的類型特徵非常簡單;請看下面的例子

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

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

和功能變得

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不需要C++ 11,它始終在C++中。 – Angew

+0

@Angew - 你的權利:是可從C++ 11獲得的「std :: enable_if」,而不是SFINAE;謝謝;回答修改 – max66

+0

如果C++ 11不是一個選項,總是有'boost :: enable_if'。 – Angew

6

確實有幾個備選方案(其中已使用長if constexpr之前就開始存在)。

一是標籤調度:

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

另外一個特點是:

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

如果您正在使用C++ 14和加速,請考慮使用Hana。用花來實現,這看起來是這樣的:

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

爲了檢測SFINAE,只有在這種情況下執行一些特定情況下,這可能是這麼簡單:

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