2017-03-08 50 views
0

這裏是我想要達到的MCVE:爲什麼我的SFINAE開關不工作?

#include <limits> 
#include <iostream> 

// enable_if (I'm stuck with a c++98 compiler) 
template<bool B, class T = void> struct enable_if {}; 
template<class T>    struct enable_if<true, T> { typedef T type; }; 

// sfinae 
template<typename T> const char* 
f(typename enable_if<std::numeric_limits<T>::is_integer, T>::type t) { return "sfinae"; } 
template<typename T> const char* 
f(T t) { return ""; } 

// test 
int main() 
{ 
    std::cout << f(3) << "\n"; // returns an empty string 
    std::cout << f(3.0) << "\n"; // returns an empty string 
} 

try it on coliru

我期待調用f(3)返回"sfinae"。我究竟做錯了什麼?

對於第一個要調用的版本,我必須手動調用f<int>(3)。我很困惑。

回答

4

下面的工作:

template <typename T> 
const char* f_impl(
    typename enable_if<std::numeric_limits<T>::is_integer, T>::type t) { 
    return "sfinae"; 
} 

template <typename T> 
const char* f_impl(
    typename enable_if<!std::numeric_limits<T>::is_integer, T>::type t) { 
    return ""; 
} 

template <typename T> 
const char* f(T t) { 
    return f_impl<T>(t); 
} 

on coliru


,如果你調用f如下您的原始代碼將工作:

std::cout << f<int>(3) << "\n"; 
std::cout << f<double>(3.0) << "\n"; 

這是因爲第一f(SFINAE o ne)將永遠無法推斷出T,因爲它位於non-deduced context之內。這意味着它將永遠不會被調用,除非你明確指定模板參數!

通過添加一個間接層,推導出T,然後顯式調用f_impl,您可以輕鬆地同時扣除和SFINAE。


在C++ 11,你甚至不需要SFINAE:

const char* f_impl(std::true_type) { return "sfinae"; } 
const char* f_impl(std::false_type) { return ""; } 

template<typename T> const char* f(T t) 
{ 
    return f_impl(std::is_integral<T>{}); 
} 
+0

事實上(感謝),但爲什麼呢? – YSC

+0

編輯說明... –

+0

@YSC:完成,有幫助嗎? –