5 回答
TA貢獻1911條經驗 獲得超7個贊
是的,使用SFINAE,您可以檢查給定的類是否提供某種方法。這是工作代碼:
#include <iostream>struct Hello{
int helloworld() { return 0; }};struct Generic {}; // SFINAE testtemplate <typename T>class has_helloworld{
typedef char one;
typedef long two;
template <typename C> static one test( typeof(&C::helloworld) ) ;
template <typename C> static two test(...); public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };};int main(int argc, char *argv[]){
std::cout << has_helloworld<Hello>::value << std::endl;
std::cout << has_helloworld<Generic>::value << std::endl;
return 0;}我剛用Linux和gcc 4.1 / 4.3測試過它。我不知道它是否可以移植到運行不同編譯器的其他平臺
TA貢獻1878條經驗 獲得超4個贊
這個問題很老,但是使用C ++ 11,我們有了一種新方法來檢查函數是否存在(或者確實存在任何非類型成員),再次依賴SFINAE:
template<class T>auto serialize_imp(std::ostream& os, T const& obj, int)
-> decltype(os << obj, void()){
os << obj;}template<class T>auto serialize_imp(std::ostream& os, T const& obj, long)
-> decltype(obj.stream(os), void()){
obj.stream(os);}template<class T>auto serialize(std::ostream& os, T const& obj)
-> decltype(serialize_imp(os, obj, 0), void()){
serialize_imp(os, obj, 0);}現在進行一些解釋。首先,如果內部的第一個表達式無效(也就是說,函數不存在),我使用表達式SFINAEserialize(_imp)從重載解析中排除函數decltype。
本void()是用來做的所有這些函數的返回類型void。
如果兩者都可用,則該0參數用于優先選擇重載os << obj(文字0是類型的int,因此第一個重載是更好的匹配)。
現在,您可能需要一個特征來檢查函數是否存在。幸運的是,寫起來很容易。但是請注意,您需要為自己想要的每個不同的函數名自己編寫一個特征。
#include <type_traits>template<class>struct sfinae_true : std::true_type{};namespace detail{
template<class T, class A0>
static auto test_stream(int)
-> sfinae_true<decltype(std::declval<T>().stream(std::declval<A0>()))>;
template<class, class A0>
static auto test_stream(long) -> std::false_type;} // detail::template<class T, class Arg>struct has_stream :
decltype(detail::test_stream<T, Arg>(0)){};并解釋。首先,sfinae_true是一個幫助器類型,它基本上與寫入相同decltype(void(std::declval<T>().stream(a0)), std::true_type{})。優點是它更短。
接下來,取決于簽入是否失敗,struct has_stream : decltype(...)從任一端std::true_type或std::false_type最后繼承。 最后,為您提供所傳遞的任何類型的“值”,而無需您知道如何構建它。請注意,這只能在未評估的上下文中使用,例如,和其他。decltypetest_streamstd::declvaldecltypesizeof
請注意,decltype不一定需要,因為sizeof(并且所有未評估的上下文)都獲得了增強。它只是decltype已經提供了一種類型,因此只是更清潔。這是一個sizeof重載的版本:
template<class T>void serialize_imp(std::ostream& os, T const& obj, int,
int(*)[sizeof((os << obj),0)] = 0){
os << obj;}由于同樣的原因,int和long參數仍然存在。數組指針用于提供sizeof可以使用的上下文。
TA貢獻1799條經驗 獲得超8個贊
雖然這個問題已經有兩年了,但我還是敢補充一下。希望它能澄清以前無可爭議的優秀解決方案。我采用了Nicola Bonelli和Johannes Schaub的非常有用的答案,并將它們合并為一個解決方案,即恕我直言,更易讀,更清晰,不需要typeof擴展:
template <class Type>class TypeHasToString{
// This type won't compile if the second template parameter isn't of type T,
// so I can put a function pointer type in the first parameter and the function
// itself in the second thus checking that the function has a specific signature.
template <typename T, T> struct TypeCheck;
typedef char Yes;
typedef long No;
// A helper struct to hold the declaration of the function pointer.
// Change it if the function signature changes.
template <typename T> struct ToString
{
typedef void (T::*fptr)();
};
template <typename T> static Yes HasToString(TypeCheck< typename ToString<T>::fptr, &T::toString >*);
template <typename T> static No HasToString(...);public:
static bool const value = (sizeof(HasToString<Type>(0)) == sizeof(Yes));};我用gcc 4.1.2檢查了它。這個功勞主要歸功于Nicola Bonelli和Johannes Schaub,如果我的回答可以幫助你,請給他們一個投票:)
- 5 回答
- 0 關注
- 710 瀏覽
添加回答
舉報
