2014-06-21 102 views
10

之間不同的輸出考慮下面的例子:窄化int在SFINAE BOOL,gcc和鐺

template<int i> 
struct nice_type; 

template<class T> 
struct is_nice : std::false_type {}; 

template<int i> 
struct is_nice< nice_type<i> > : std::integral_constant<int, i> {}; 

template<class T, class = void> 
struct pick 
{ 
    typedef std::integral_constant<int, -1> type; 
}; 

template<class T> 
struct pick<T, typename std::enable_if< is_nice<T>::value >::type > 
{ 
    typedef std::integral_constant<int, is_nice<T>::value > type; 
}; 

int main() 
{ 
    std::cout << pick<int>::type::value << ", "; 
    std::cout << pick< nice_type<42> >::type::value << std::endl; 
    return 0; 
} 

鏘(3.4.1)輸出 「1,-1」,而GCC(4.9.0)輸出「-1,42」。

問題存在於pick的專業化中。雖然海灣合作委員會似乎很樂意將is_nice<T>::value(42)轉換爲bool(true),但clang並沒有這樣做,並放棄了專業化。這兩個示例均使用-std=c++11編譯。

哪個編譯器是正確的?

+1

您的意思是'nice_type',而不是'cool_type'在第8行? –

+0

@RSahu是的,對不起。 – sbabbi

+0

那是什麼? –

回答

9

這是gcc錯誤57891。積分常數42bool的轉換涉及縮小轉換,這在非類型模板參數中是不允許的。因此,enable_if是不合格的,並且pick專業化應該被放棄,正如叮噹正確。

§14.3.2/ 5 [temp.arg.nontype]

The following conversions are performed on each expression used as a non-type template-argument. If a non-type template-argument cannot be converted to the type of the corresponding template-parameter then the program is ill-formed.
— For a non-type template-parameter of integral or enumeration type, conversions permitted in a converted constant expression (5.19) are applied.
...

§5.19/ 3 [expr.const]

... A converted constant expression of type T is an expression, implicitly converted to a prvalue of type T , where the converted expression is a core constant expression and the implicit conversion sequence contains only user-defined conversions, lvalue-to-rvalue conversions (4.1), integral promotions (4.5), and integral conversions (4.7) other than narrowing conversions (8.5.4).

§8.5.4/ 7 [dcl.init.list]

A narrowing conversion is an implicit conversion
...
— from an integer type or unscoped enumeration type to an integer type that cannot represent all the values of the original type, except where the source is a constant expression whose value after integral promotions will fit into the target type.


minimal example表明gcc的錯誤:

template<bool> 
struct foo{}; 
foo<10> f; 

int main() {} 

GCC-4.9接受的代碼,而鐺-3.4,出現以下錯誤拒絕它:

error: non-type template argument evaluates to 10, which cannot be narrowed to type 'bool' [-Wc++11-narrowing]

foo<10> f; 
    ^

的修復您的特殊問題很簡單。確保非類型模板參數enable_if計算結果爲bool

template<class T> 
struct pick<T, typename std::enable_if< is_nice<T>::value != 0 >::type > 
//              ^^^^^^ 
{ 
    typedef std::integral_constant<int, is_nice<T>::value > type; 
};