2011-01-23 119 views
1

我一直在嘗試改編this 解決方案,以啓用普通(非成員)函數的存在。 在我的例子中,我有很多全局的字符串實用程序類型的函數,它們使用任何字符串類型T,例如T有一個char const* c_str() const成員函數。調整檢查函數參數是否存在成員函數

目標是消除奇怪的編譯器錯誤消息,如果用戶試圖傳遞一些沒有c_str()成員函數的類型T,而不是編譯器說的「c_str():no such member function」,I' d而是編譯器說:「foo(T &):沒有這樣的函數」其中foo是全局函數。

這裏是適應代碼:

template<bool B,typename T = void> 
struct enable_if { 
    typedef T type; 
}; 

template<typename T> 
struct enable_if<false,T> { 
}; 

// 
// This macro is adapted from the linked-to question -- this part works fine. 
// 
#define DECL_HAS_MEM_FN(FN_NAME)           \ 
    template<class ClassType,typename MemFnSig>        \ 
    struct has_##FN_NAME##_type {            \ 
    typedef char yes[1];             \ 
    typedef char no[2];              \ 
    template<typename T,T> struct type_check;        \ 
    template<class T> static yes& has(type_check<MemFnSig,&T::FN_NAME>*); \ 
    template<class T> static no& has(...);        \ 
    enum { value = sizeof(has<ClassType>(0)) == sizeof(yes) };   \ 
    } 

// Declare an instance of the above type that checks for "c_str()". 
DECL_HAS_MEM_FN(c_str); 

// Define another macro just to make life easier. 
#define has_c_str(STRINGTYPE) \ 
    has_c_str_type<STRINGTYPE,char const* (STRINGTYPE::*)() const>::value 

// 
// A "ValidatedStringType" is a StringType that uses the above machinery to ensure that 
// StringType has a c_str() member function 
// 
template<class StringType> 
struct ValidatedStringType { 
    typedef typename enable_if<has_c_str(StringType),StringType>::type type; 
}; 

// Here's the global function where I want to accept only validated StringTypes. 
template<class StringType> 
void f(typename ValidatedStringType<StringType>::type const& s) { 
} 

struct S { // Class for testing that has c_str(). 
    char const* c_str() const { 
    return 0; 
    } 
}; 

struct N { // Class for testing that does not have c_str(). 
}; 

using namespace std; 

int main() { 
    S s; 
    N n; 
    cout << has_c_str(S) << endl; // correctly prints '1' 
    cout << has_c_str(N) << endl; // correctly prints '0' 
    f(s); // error: no matching function for call to 'f(S&)' 
} 

然而,如上圖所示,編譯器不「看」 f(S&) - 爲什麼不呢?

+0

僅供參考:f()採用S const而不僅僅是S沒有區別。同樣使's'const沒有任何區別。最後,消除'&'沒有任何區別。 – 2011-01-23 04:35:37

回答

1

如果我理解正確的問題,應用enable_iff自己喜歡 下面將解決這個問題:

template<class StringType> 
typename enable_if<has_c_str(StringType),StringType>::type 
f(StringType const& s) {....} 

希望這有助於。

+0

但f的返回類型應該是無效的。如果省略「,StringType」,那麼它是正確的並且可行。 :)但我仍然想知道爲什麼原稿不起作用。 – 2011-01-23 15:44:04

0

我無法回答你的問題(「爲什麼不?」),但我可以提供解決方法。但是,男人,這是醜陋的。您最終定義爲每一個功能的結構和功能:

template<class StringType, class T = typename ValidatedStringType<StringType>::type> 
struct f_helper { 
    void operator()(T const& s) { 
     // Put the contents of f() here 
    } 
}; 

template<class StringType> 
void f(StringType const &s) { 
    f_helper<StringType>()(s); 
} 

我敢肯定有,你可以寫,以消除一些樣板的一些預處理魔術,但它也將是相當難看:

#define DECL_VALIDATED_FUNC(RetType, name, Validator, contents) \ 
    template<class StringType, class T = typename Validator<StringType>::type> \ 
    struct name ## _helper { \ 
    RetType operator()(T const& s) contents \ 
    }; \ 
    \ 
    template<class StringType> \ 
    RetType name(StringType const& s) { \ 
    name ## _helper<StringType>()(s); \ 
} 

DECL_VALIDATED_FUNC(void, f, ValidatedStringType, { 
    // put contents of f() here 
}) // note the closing parenthesis 

不幸的是,你不能指定默認模板參數,以免費的功能,否則你可以做:

template<class StringType, class T = typename ValidatedStringType<StringType>::type> 
void f(T const& s) {} 
+0

是的,爲了使錯誤信息更好,這太有點太醜陋了。 – 2011-01-23 04:32:59