有没有办法得到一个对象存在函数的否定?

时间:2017-10-26 13:16:58

标签: c++ c++11 templates sfinae typetraits

要确定某个函数是否存在函数,可以使用以下命令:

template <typename...Ts>
using void_t = void;

void fn(int);

struct X {};

template <typename T, typename = void_t<decltype(fn(std::declval<T>()))>>
void fn2(T) { }

void test() {
  fn2(int(1)); // works
  //fn2(X()); // doesn't work
}

现在,有没有办法检测fn(T)类型T是否不存在?

示例:

void test2() {
  //fn2(int(1)); // doesn't work
  fn2(X()); // works
}

这样做的原因是定义一个排除操作,以便我可以为两者定义fn2()以避免歧义错误。

2 个答案:

答案 0 :(得分:4)

通常的做法是制作一种类型特征,正如@chris所说:

template <typename T, typename = void>
struct fn_callable_with : std::false_type {};
template <typename T>
struct fn_callable_with<T, void_t<decltype(fn(std::declval<T>()))>> : std::true_type {};

// For bonus C++14 points:
// template <typename T>
// /*C++17: inline*/ constexpr bool fn_callable_with_v = fn_callable_with<T>::value;

template <typename T, typename = typename std::enable_if<!fn_callable_with<T>::value>::type>
// C++14: template <typename T, typename = std::enable_if_t<!fn_callable_with_v<T>>>
void fn2(T) { }

答案 1 :(得分:1)

你需要fn2的另一个重载,否则SFINAE不会做任何有用的事情。

void fn2(...) { } // called if the overload below is SFINAEd away

template <typename T, typename = void_t<decltype(fn(std::declval<T>()))>>
void fn2(T) { }

live example on wandbox

这个想法是SFINAE可以从过载集中删除候选者。如果fn2是唯一的候选人,那么您将会遇到严重错误。