问题
I created a code below to test whether there is an operator+ overload for 2 classes:
template<typename T, typename U>
struct _has_plus_hlp {
template<typename X, typename Y>
static std::true_type _check(X&, Y&, decltype(std::declval<X>() + std::declval<Y>()) = {});
static std::false_type _check(...);
using type = decltype(_check(std::declval<T>(), std::declval<U>()));
};
template<typename X, typename Y>
constexpr bool has_plus_v = _has_plus_hlp<X, Y>::type::value;
int main()
{
std::cout << std::boolalpha << detail::has_plus_v<int, std::string> << std::endl;
auto f = [](auto& a, auto& b) {
std::cout << std::boolalpha << detail::has_plus_v<decltype(a), decltype(b)> << std::endl;
};
std::string str = "HELLO";
int num = 5;
f(num, str);
}
This is what I got for g++ (7.4.0):
false
true
Whereas I expect both to be false as in case of clang:
false
false
Did I got something wrong?
回答1:
Your original version doesn't work because std::declval<>
returns an r-value and a regular reference can't bind to it. A fix is to bind to a forwarding reference:
static std::true_type _check(X&&, Y&&, decltype(std::declval<X>() + std::declval<Y>()) = {});
A slightly simpler version:
template<class T, class U>
auto has_plus_test(T&& t, U&& u) -> decltype(static_cast<void>(t + u), std::true_type{});
std::false_type has_plus_test(...);
template<class T, class U>
using has_plus = decltype(has_plus_test(std::declval<T>(), std::declval<U>()));
template<class T, class U>
constexpr bool has_plus_v = has_plus<T, U>::value;
int main() {
std::cout << std::boolalpha << has_plus_v<int, int> << '\n'; // Outputs true.
std::cout << std::boolalpha << has_plus_v<int, std::string> << '\n'; // Outputs false.
std::cout << std::boolalpha << has_plus_v<std::string, std::string> << '\n'; // Outputs true.
}
来源:https://stackoverflow.com/questions/57292886/gcc-check-whether-the-given-class-has-operator