namespace details {
template<template<class...>class, class, class...>
struct can_apply:std::false_type{};
// C++17 has void_t. It is useful. Here is a short implementation:
template<class...>struct voider{using type=void;};
template<class...Ts>using void_t=typename voider<Ts...>::type;
template<template<class...>class Z, class...Ts>
struct can_apply<Z, 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 A, class B>
using add_result = decltype( std::declval<A>()+std::declval<B>() );
template<class A, class B>
using can_add = can_apply< add_result, A, B >;
现在can_add<int, int> 是(继承自)std::true_type,而can_add<std::string, void*> 是(继承自)std::false_type。
现在,如果您使用的是非 MSVC c++14 编译器,则可以:
template<class A, class B,
std::enable_if_t<can_add<A&,B&>{}, int> =0
>
void only_addable( A a, B b ) {
a+b; // guaranteed to compile, if not link
}
或
template<class A, class B>
std::enable_if_t<can_add<A&,B&>{}, void> // void is return value
only_addable( A a, B b ) {
a+b; // guaranteed to compile, if not link
}
在c++2a 中,概念提案将使这种语法更清晰。
有一个is_detected 的提案,它的作用类似于我上面的can_apply。
add_result 的 declval 部分很烦人。缺乏概念,我不知道如何干净地删除它。