我遇到了C++中的Member Detector成語,它是一種類型特徵,用於判斷類是否包含某個特定名稱的成員。但是,如果類型不是類,鏈接示例不能正常工作:我希望false
結果適用於任何非類類型。一個可能的解決方案肯定是這樣的,使用boost::is_class<T>
:SFINAE用於類型實例
template<typename T>
struct general_DetectX : boost::mpl::and_<
boost::is_class<T>,
DetectX<T> >::type
{ };
bool hasX = general_DetectX<int>::value; // hasX = false
但這個問題是關於爲什麼當初DetectX<T>
產生錯誤的,而不是做的事情SFINAE。下面是鏈接碼的相關部分的摘錄(局部結構Fallback
和Check<U,U>
和類型定義ArrayOfOne
,ArrayOfTwo
和type
爲了簡潔移除):
template<typename T>
class DetectX
{
struct Derived : T, Fallback { };
template<typename U>
static ArrayOfOne & func(Check<int Fallback::*, &U::X> *);
template<typename U>
static ArrayOfTwo & func(...);
public:
enum { value = sizeof(func<Derived>(0)) == 2 };
};
它可以看出,DetectX::Derived
使用任何過載分辨率以外,所以不會調用SFINAE處理錯誤的規則。但是,這是可以改變的地方使用Derived
不發生的重載決議的一部分:
template<typename T>
class DetectX
{
template<typename U>
struct Derived : U, Fallback { };
template<typename U>
static ArrayOfOne & func(Check<int Fallback::*, &Derived<U>::X> *);
template<typename U>
static ArrayOfTwo & func(...);
public:
enum { value = sizeof(func<T>(0)) == 2 };
};
試圖實例第一func()
過載時Derived<T>
模板只實例化,所以爲什麼我仍然得到錯誤即使是修改後的版本?這裏有一個例子:
$ g++ --version | head -n1
g++ (GCC) 4.8.2
$ g++ -c demo.cxx
demo.cxx: In instantiation of 'struct DetectX<int>::Derived<int>':
demo.cxx:16:53: required by substitution of 'template<class U> static char (& DetectX<T>::func(DetectX<T>::Check<int DetectX<T>::Fallback::*, (& DetectX<T>::Derived<U>::X)>*))[1] [with U = U; T = int] [with U = int]'
demo.cxx:24:31: required from 'class DetectX<int>'
demo.cxx:27:25: required from here
demo.cxx:7:12: error: base type 'int' fails to be a struct or class type
struct Derived : U, Fallback { };
^
它失敗了,因爲替換髮生在基類列表*其中*任何錯誤都會導致硬錯誤而不是軟錯誤(SFINAE)。換句話說,SFINAE不會出現在基類中。 – Nawaz
@Nawaz感謝您的評論,介紹我的硬和軟錯誤。但是我需要Jarod42在他的答案中提供的http://stackoverflow.com/questions/15260685鏈接來獲取上下文。 –