如果另一个函数不存在,C ++定义一个函数

时间:2017-02-07 22:55:14

标签: c++ swap template-meta-programming sfinae

在C ++ 11及更高版本中,您可以使用以下模式以简单的方式执行成员检测:

template <typename MyClass>
auto swap(MyClass &lhs, MyClass &rhs) -> decltype (lhs.swap(rhs), void())
{
    std::cout << "Swapping LHS with RHS by calling the member function!\n";
    lhs.swap(rhs);
}

也就是说,通过使用延迟返回类型,我们可以使用lhs中的rhsdecltype以及decltype中的多个表达式可以使用逗号运算符链接。如果包含的表达式无效,decltype将无法进行类型检查,但这不会引发编译器错误,而是触发SFINAE,因为它在类型解析期间遇到。

以上代码完美无缺,只要:

  • MyClass不是我们当前类的CRDT子类,因为在这种情况下由于继承,当前类首先被编译,因此无法访问子类中定义的成员类。
  • 这不能用于反过来:只有在另一个函数存在的情况下才定义函数实现。

这就是这个问题:

如果另一个成员函数存在,如何才能定义(n重载模板)函数?

例如,上面的例子定义了一个包含swap(lhs, rhs)函数的lhs.swap(rhs)。但是,如果lhs.swap(rhs)不存在,我想创建一个替代变体,而不是调用lhs.swap(rhs),而是调用std::swap(lhs, rhs)

请注意,我不想在这里使用ADL查找,因为这是重点:我们的想法是为任何只有(可能){{1}的类提供swap(lhs, rhs)函数。函数定义。

如何做到这一点?

1 个答案:

答案 0 :(得分:3)

您需要使用std::enable_if

这是一个例子。为简单起见,我使用相同方法的不同公式来检测成员的存在,并将其包装在特征has_member_swap中。

template <typename... T> struct make_void { typedef void type; };
template <typename... T> using void_t = typename make_void<T...>::type;

template <typename, typename, typename = void>
struct has_member_swap : std::false_type { };
template <typename T1, typename T2>
struct has_member_swap<T1, T2,
  void_t<decltype( std::declval<T1&>().swap(std::declval<T2&>()) )>
> : std::true_type { };

template <typename T>
std::enable_if_t<has_member_swap<T,T>::value> swap(T& lhs, T& rhs) {
  lhs.swap(rhs);
}

template <typename T>
std::enable_if_t<!has_member_swap<T,T>::value> swap(T& lhs, T& rhs) {
  std::swap(lhs,rhs);
}
从c ++ 17开始,

std::void_t可用。