2012-04-26 56 views
5

SFINAE有問題。我需要能夠確定一個Type是否有一個成員函數operator-> defined,而不管它的返回類型。示例如下。SFINAE - 嘗試確定模板類型是否具有「變量」返回類型的成員函數

這個類在測試儀中。它用一個返回類型X *定義了operator - >()。因此我不會知道'X'是什麼地方硬編碼到處。

template <class X> 
class PointerX 
{ 
    ... 

    X* operator->() const; 
    ... 
} 

該類試圖確定傳入的T是否有一個方法operator-> defined;不管什麼運營商 - >返回類型。

template<typename T> 
struct HasOperatorMemberAccessor 
{ 
    template <typename R, typename C> static R GetReturnType(R (C::*)()const); 

    template<typename U, typename R, R(U::*)()const> struct SFINAE{}; 
    template<typename U> static char Test(SFINAE<U,  decltype(GetReturnType(&U::operator->)), &U::operator-> >*); 
    template<typename U> static uint Test(...); 
    static const bool value = sizeof(Test<T>(0)) == sizeof(char); 
}; 

除了operator-> return類型必須是'Object'之外,該類與上面完全相同。

template<typename T> 
struct HasOperatorMemberAccessorOBJECT 
{ 
    template <typename R, typename C> static R GetReturnType(R (C::*)()const); 

    template<typename U, typename R, R(U::*)()const> struct SFINAE{}; 
    template<typename U> static char Test(SFINAE<U,  Object*,    &U::operator-> >*); // only change is we hardcoded Object as return type. 
    template<typename U> static uint Test(...); 
    static const bool value = sizeof(Test<T>(0)) == sizeof(char); 
}; 

結果:

void main() 
{ 
    HasOperatorMemberAccessor<PointerX<Object>>::Test<PointerX<Object>>(0);   // fails ::value is false; Test => Test(...) 

    HasOperatorMemberAccessorOBJECT<PointerX<Object>>::Test<PointerX<Object>>(0);  // works! ::value is true; Test => Test(SFINAE<>*) 
} 

HasOperatorMemberAccessor無法找到PointX的成員函數 「對象操作符 - >()const的」。因此它使用Test的通用版本Test(...)。

然而,HasOperatorMemberAccessorOBJECT能夠找到PointX的 「對象操作符 - >()const的」。因此它使用Test專業版本測試(SFINAE *)。

雙方應該已經能夠找到「對象操作符 - >()const的」方法;因此兩者都應該使用Test的專業版本測試(SFINAE *);因此HasOperatorMemberAccessor> :: value對於兩者都應該爲true。

HasOperatorMemberAccessor和HasOperatorMemberAccessorOBJECT之間的唯一區別是,HasOperatorMemberAccessorOBJECT具有硬編碼到對象類型名稱R,

所以問題是,「decltype(GetReturnType(&û::操作符 - >))」沒有返回對象正確。我已經嘗試了許多不同的發現返回類型的許可證。他們走如下:

decltype(GetReturnType(&U::operator->)) 
    typename decltype(GetReturnType(&U::operator->)) 
    decltype(((U*)nullptr)->operator->()) 
    typename decltype(((U*)nullptr)->operator->()) 

沒有工作,爲什麼?我正在使用MSVC++ 10.0。

+0

一件事是,'PointerX ::操作符 - >''返回布爾*','不bool'。 – 2012-04-26 20:13:19

+0

就HasOperatorMemberAccessor而言,PointerX中X的類型並不重要。我試圖通過不向該示例添加許多無關對象來概括我的問題。如果它太混亂,我會改變布爾到字符串。 – 2012-04-26 20:17:57

+0

讓我再試一次.'PointerX :: operator->'returns' Object *'。 'decltype(...)'是'Object *'。 'HasOperatorMemberAccessorOBJECT'看起來成功了,儘管它用'Object'替換了'decltype(...)'。這裏看起來有些不對勁。我根本不是在討論'HasOperatorMemberAccessor'。 – 2012-04-26 20:41:57

回答

4

你問如何來實現這樣的特徵,或者爲什麼decltype,你想到的是不是正常?如果是前者,這裏有一個方法:

#include <type_traits> 

template<typename T, bool DisableB = std::is_fundamental<T>::value> 
struct HasOperatorMemberAccessor 
{ 
private: 
    typedef char no; 
    struct yes { no m[2]; }; 

    struct ambiguator { char* operator ->() { return nullptr; } }; 
    struct combined : T, ambiguator { }; 
    static combined* make(); 

    template<typename U, U> struct check_impl; 
    template<typename U> 
    static no check(
     U*, 
     check_impl<char* (ambiguator::*)(), &U::operator ->>* = nullptr 
    ); 
    static yes check(...); 

public: 
    static bool const value=std::is_same<decltype(check(make())), yes>::value; 
}; 

// false for fundamental types, else the definition of combined will fail 
template<typename T> 
struct HasOperatorMemberAccessor<T, true> : std::false_type { }; 

// true for non-void pointers 
template<typename T> 
struct HasOperatorMemberAccessor<T*, false> : 
    std::integral_constant< 
     bool, 
     !std::is_same<typename std::remove_cv<T>::type, void>::value 
    > 
{ }; 

template<typename X> 
struct PointerX 
{ 
    X* operator ->() const { return nullptr; } 
}; 

struct X { }; 

int main() 
{ 
    static_assert(
     HasOperatorMemberAccessor<PointerX<bool>>::value, 
     "PointerX<> has operator->" 
    ); 
    static_assert(
     !HasOperatorMemberAccessor<X>::value, 
     "X has no operator->" 
    ); 
    static_assert(
     HasOperatorMemberAccessor<int*>::value, 
     "int* is dereferencable" 
    ); 
    static_assert(
     !HasOperatorMemberAccessor<int>::value, 
     "int is not dereferencable" 
    ); 
    static_assert(
     !HasOperatorMemberAccessor<void*>::value, 
     "void* is not dereferencable" 
    ); 
} 

VC++ 2010沒有讓這個更清潔所需的必要的C++ 11的設施(例如表達SFINAE)。只覺眼睛

+0

那麼,除了不允許T成爲指針類型之外,這對我來說非常有用。我改變基地: 結構基礎:<!is_pointer ::值,T,無>條件::類型,base_mixin {}; 這就是說,我很想知道爲什麼decltype不起作用。 – 2012-04-26 21:09:54

+0

@MichaelG:'HasOperatorMemberAccessor <>'可以是平凡專門爲指針:'模板類HasOperatorMemberAccessor :公共的std :: true_type {};'。至於'decltype'不能像你期望的那樣工作,我沒有太多調查你的代碼,但VC++ 2010的decltype實現是預先標準化的,並且在其之上。 – ildjarn 2012-04-26 21:14:06

+0

@Michael:用適當的指針類型檢測編輯('void *'是一個疑難雜症)。 – ildjarn 2012-04-26 21:27:33

相關問題