2016-09-11 32 views
6

鑑於2種TU我想檢測是否有可能那些對象(即之間的呼叫operator *是有可能寫t * u其中tT型和uU型)檢測操作人員是否存在,在C調用++(考慮static_asserts)

我使用c++ detection idiom的,但因爲它沒有在我的編譯器可我實現了我自己這樣

struct nonesuch { 
    nonesuch() = delete; 
    ~nonesuch() = delete; 
    nonesuch(nonesuch const&) = delete; 
    void operator=(nonesuch const&) = delete; 
}; 

namespace detail { 
template <class Default, class AlwaysVoid, template<class...> class Op, class... Args> 
struct detector { 
    using value_t = std::false_type; 
    using type = Default; 
}; 

template <class Default, template<class...> class Op, class... Args> 
struct detector<Default, std::void_t<Op<Args...>>, Op, Args...> { 
    using value_t = std::true_type; 
    using type = Op<Args...>; 
}; 

} // namespace detail 

template <template<class...> class Op, class... Args> 
using is_detected = typename detail::detector<nonesuch, void, Op, Args...>::value_t; 

template< template<class...> class Op, class... Args > 
constexpr bool is_detected_v = is_detected<Op, Args...>::value; 

無W I有這樣的幫手:

template <typename T, typename U> 
using multiply = decltype(std::declval<T>() * std::declval<U>()); 

,並檢測它是否是可調用我打電話

bool can_multiply = is_detected_v<multiply, T, U> 

這幾乎是罰款,例如該打印1,0預期

std::cout << is_detected_v<multiply, int, int> << std::endl; 
std::cout << is_detected_v<multiply, std::vector<int>, std::vector<int>> << std::endl; 

但現在我有課

template<typename T> 
class A { 
}; 

template<typename T> 
A<T> operator*(const A<T>&, const A<T>&) { 
    static_assert(!std::is_same<bool, T>::value); 
    return A<T>(); 
} 

這裏A<bool>不能A<bool>相乘,但我的代碼檢測,它可能

std::cout << is_detected_v<multiply, A<bool>, A<bool>> << std::endl; // 1 
A<bool>() * A<bool>(); // does't compile 

所以,我的問題是,如何修復我的代碼無法檢測方法時,他們static_asserted了呢?我想我可以代替static_assert一些SFINAE,但我不想(因爲我沒有獲得再說static_asserts有更好的錯誤信息)。

回答

7

所以,我的問題是,如何解決我的代碼,當他們static_asserted出不檢測方法?

你根本無法。這只是static_assert的缺點之一 - 無法從外部驗證操作的有效性。這是因爲static_assert不會在operator*實例化的「直接背景」發生,所以SFINAE不適用 - 它永遠是一個嚴重的錯誤。

我想我可以用一些sfinae替換static_assert,但我不想(因爲我沒有訪問權限,除了static_asserts有更好的錯誤信息)。

我很同情。但這基本上是權衡。 SFINAE和類型檢查,或者static_assert和更清楚的錯誤。 (當然在這種情況下,你可以只寫一個非模板A<bool> operator*(A<bool> const&, A<bool> const&),但這可能除了重點)。

+0

解釋爲什麼可能會幫助(SFINAE支票必須重載期間進行;迫使每一個編譯器來編譯每個函數,並確定是否有任何非法的代碼之前,確定哪些超載要求編譯器作者都希望能努力,並可能導致在令人驚訝的行爲中(因爲你的'T *'代碼包含一個導致錯誤代碼2級嵌套深的錯誤),所以'我更喜歡void *'over'T *'。 SFINAE檢查是一種妥協,即使在那裏,MSVC也會對他們造成嚴重影響。 – Yakk