namespace details {
template<template<class...>class Z, class, class...Ts>
struct can_apply : std::false_type{};
template<template<class...>class Z, class...Ts>
struct can_apply<Z, std::void_t<Z<Ts...>>, Ts...> : std::true_type{};
}
template<template<class...>class Z, class...Ts>
using can_apply = details::can_apply<Z,void, Ts...>
template<class Sig>
using can_invoke = can_apply< std::result_of_t, Sig >;
我們現在有一個特性類can_invoke
。
你傳給它一個簽名。如果簽名是一個有效的電話,這是真誠的,否則就是錯誤的。
template<class T>
std::enable_if_t< !can_invoke<T()> >
use_this(T obj) {
obj->do_stuff();
}
template<class T>
std::enable_if_t< can_invoke<T()> >
use_this(T func) {
use_this(func());
}
我使用一些C++ 11,如enable_if_t
,void_t
和result_of_t
。所有這些都很容易在C++ 11中編寫,而且很容易搜索。
通過當一個無效簽名被修改在C++ 14的result_of
行爲。在C++ 11中,它不一定是SFINAE友好的。我們可以在C++ 11如下與invoke_result_r
替換std::result_of_t
:
template<class Sig, class=void>
struct invoke_result {};
template<class Sig>
using invoke_result = typename invoke_result<Sig>::type;
template<class F, class...Args>
struct invoke_result<F(Args...),
decltype(void(std::declval<F>()(std::declval<Args>()...)))
> {
using type = decltype(std::declval<F>()(std::declval<Args>()...));
};
這是現在SFINAE友好。
can_apply
是類似於C++ 20的is_detected
,但較短的和對點。
注意,在非C++編譯器11這樣,像MSVC,是不切實際的。但是,您可以使用標籤分派進行類似的操作。