2016-09-27 94 views
1

這個問題真的沒有背景。用戶自定義轉換的SFINAE

使用SFINAE(直接或間接使用type_traits)檢查現有函數,成員函數等等的方法有很多。但是:

第一個問題:有什麼辦法來檢查一個類是否實現了一個特定的用戶定義的轉換運算符?

爲了說明我的意思,請考慮這段代碼。我想沒有任何斷言失敗運行這段代碼:

#include <type_traits> 
#include <cassert> 

struct NotADouble { 
}; 
struct Double { 
    // explicit or not - you decide 
    explicit operator double() { 
     return 1.; 
    } 
}; 
// CORRECT THIS: ... 
template<typename T, 
    class = decltype(static_cast<double>(std::declval<T>()))> 
int f(T) { 
    return 1; 
} 
int f(...) { 
    return 2; 
} 
// ... UNTIL HERE 

int main() { 
    assert(f(NotADouble()) == 2); 
    assert(f(Double()) == 1); 
    assert(f(3.) == 2); 
    assert(f(3) == 2); 
    assert(f(3.f) == 2); 
} 

目前執行的f檢查是否有從Tdouble任何標準的轉換過程,我想這是與在這種情況下std::is_convertible

另一種方法是以下實現,它接受前兩個測試。

template<typename T> 
int f(T, double (T::*)() = nullptr) { 
    return 1; 
} 
int f(...) { 
    return 2; 
} 

問題2:即使NotADouble沒有實現任何轉換操作符,它似乎讓這個成員函數指針。因此,究竟是什麼double (T::*)()以及爲什麼它存在於任何類?

回答

0

第一個問題:可以創建輔助結構來檢查是否存在在給定的結構(C++ 14碼)所定義的轉換運算符:

#include <type_traits> 
#include <iostream> 

struct NotDouble { }; 
struct Double { 
    explicit operator double() { 
     return 1.0; 
    } 
}; 

template <class From, class To, class = void> 
struct HasConversionOperator: std::false_type { }; 

template <class From, class To> 
struct HasConversionOperator<From, To, decltype((&From::operator To), void())>: std::true_type { }; 

template <class From, class To, class = void> 
struct HasExplicitConversion: std::false_type {}; 

template <class From, class To> 
struct HasExplicitConversion<From, To, decltype(std::declval<To&>() = (To)std::declval<From&>(), void())>: std::true_type { }; 

template <class From, class To, class = void> 
struct HasImplicitConversion: std::false_type {}; 

template <class From, class To> 
struct HasImplicitConversion<From, To, decltype(std::declval<To&>() = std::declval<From&>(), void())>: std::true_type { }; 

template <class T> 
std::enable_if_t<HasConversionOperator<T, double>::value && HasExplicitConversion<T, double>::value && !HasImplicitConversion<T, double>::value> is_double(T d) { 
    std::cout << "has conversion to double" << std::endl; 
} 

template <class T> 
std::enable_if_t<!HasConversionOperator<T, double>::value || !HasExplicitConversion<T, double>::value || HasImplicitConversion<T, double>::value> is_double(T) { 
    std::cout << "don't have conversion to double" << std::endl; 
} 

int main() { 
    is_double(Double{}); 
    is_double(NotDouble{}); 
} 

輸出:

has conversion to double 
don't have conversion to double 

第二個問題:double (T::*)()是任何成員的類型函數指針與所有者T返回一個不帶任何參數的double。請記住,不僅轉換經營者有這樣的簽名。更重要的是,即使類T沒有任何成員函數返回double並且不帶任何參數,它完全允許創建這樣的指針類型,只是不能用任何值填充指針類型的變量。

+0

我曾嘗試過類似的測試,但沒有參考,這顯然是不夠的... – overseas

+0

@ user3445587您的意思是'操作符(&)的地址。很遺憾,沒有辦法採用成員函數引用,這顯然是一個缺點,但它直接歸功於C++方法調用語法。例如。在'a.foo();'應該怎樣解釋'foo'?作爲'a'的成員函數或範圍中可用的成員函數引用...? –