【问题标题】:C++ define a function iff another function does not exist如果另一个函数不存在,C++ 定义一个函数
【发布时间】:2017-02-07 22:55:13
【问题描述】:

在 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 子类,因为在这种情况下,由于继承,当前类首先被编译,因此还不能访问子类中定义的成员。
  • 这不能用于反其道而行之:仅当另一个函数存在时才定义一个函数实现。

这就是这个问题的目的:

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

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

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

如何做到这一点?

【问题讨论】:

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


    【解决方案1】:

    您需要为此使用std::enable_if

    这是一个例子。为简单起见,我使用相同方法的不同公式来检测成员的存在,并将其包装在 trait 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 开始可用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-15
      • 1970-01-01
      • 1970-01-01
      • 2015-07-10
      • 2011-12-11
      • 1970-01-01
      相关资源
      最近更新 更多