C++定义一个函数当且仅当另一个函数不存在

标签 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);
}

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

以上代码可以完美运行,只要:

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

这就是这个问题的内容:

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

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

请注意,我不想在这里使用 ADL 查找,因为这就是重点:想法是为任何仅(可能)具有lhs.swap(rhs) 函数定义。

如何做到这一点?

最佳答案

您需要使用 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);
}

std::void_t从 c++17 开始可用。

关于C++定义一个函数当且仅当另一个函数不存在,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42101566/

相关文章:

binary - 在 Perforce 中交换文件

c++ - boost 不返回类型

c++ - 用它的索引范围打包元组

c++ - 在c++中的macOS Catalina上编译 header 和cpp文件的问题

c++ - OpenGL 模板测试发生在片段程序运行之前还是之后?

c - C中字符串中的字母互换

c++ - 在没有额外内存的情况下移动数组中的一系列元素?

c++ - 多维 std::intializer_list,其中维数指定为其类的模板参数

C++ Boost 等待无法识别

c++ - 将引用参数分配给局部变量