SFINAE检查运算符+=

SFINAE check for operator+=

本文关键字:运算符 检查 SFINAE      更新时间:2023-10-16

如果缺少operator+=,我将尝试从过载集中消除过载。

我知道如何检查T+T是否合法:

template<typename T,
         typename CheckTplusT = decltype(std::declval<T>() + std::declval<T>())>
void foo(T a, T b, ...)
{
  a = a + b;
}

但这对+= 不起作用

template<typename T,
         typename CheckTplusT = decltype(std::declval<T>() += std::declval<T>())>
void foo(T a, T b, ...)
{
  a += b;
}

这是可以通过在decltype中使用另一个表达来解决的吗?还是我需要另一个SFINAE构建体?

我需要从重载集中消除这一点的原因是,它与另一个重载冲突,后者接受一个函子作为+=的替代。编译器是VS2013、gcc4.8

我会把第二个表单写成:

template<typename T>
auto foo(T a, T b, ...) -> decltype( a+=b, void() )
{
  a += b;
}

如果表达式a+=b有效,则decltype(a+=b, void())的推导类型将仅为void,否则将导致SFINAE。

好吧,即使在第一种形式中,我也会使用尾随返回类型的方法。

您需要+=左侧的lvalue,但您的解决方案具有x值。正如dyp在评论中所说,您可以使用declval<T&>来获得一个左值。这很好用(刚刚测试过):

template<typename T,
         typename CheckTplusT = decltype(std::declval<T&>() += std::declval<T>())>
void foo(T a, T b, ...)
{
}

这个怎么样?这是CCD_ 12之前使用的方法。

template<typename T,
         typename CheckTplusT = decltype(*(T*)nullptr += std::declval<T>())>
void foo(T a, T b, ...)
{
  a += b;
  std::cout << "foo with +=" << std::endl;
}

添加此main()函数:

int main()
{
    int x = 1, y = 2;
    foo( x, y );
}

这就是编译器错误:

 main.cpp: In function int main():  main.cpp:15:15: error: no matching
 function for call to foo(int&, int&)
      foo( x, y );
            ^  main.cpp:15:15: note: candidate is:  
 main.cpp:7:6: note: template<class T, class CheckTplusT> void foo(T, T, ...)  void
 foo(T a, T b, ...)
   ^ main.cpp:7:6: note:   template argument deduction/substitution failed: 
    main.cpp:6:60: error:    
      using xvalue (rvalue reference) as lvalue
       typename CheckTplusT = decltype(std::declval<T>() += std::declval<T>())>

关键线路为using xvalue (rvalue reference) as lvalue

这是清除的文档

这个变通方法对我有效:

template<typename T,
     typename CheckTpluseqT = decltype(*std::declval<T*>() += *std::declval<T*>())>
void foo(T &a, T b, ...)
{
   a += b;
 }
int main()
{
   int a = 1, b = 2;
   foo( a, b );
   std::cout << a << std::endl;
}

输出3

当然,您也可以使用declval<T&>