SFINAE检查操作员+ =

时间:2014-10-01 10:16:56

标签: c++ sfinae

如果缺少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构造?

我需要从过载集中消除它的原因是它与另一个重载冲突,该重载接受一个functor用作+=的替代。编译器是VS2013,gcc4.8

4 个答案:

答案 0 :(得分:16)

我会把第二种形式写成:

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

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

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

答案 1 :(得分:12)

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

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

答案 2 :(得分:1)

添加此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

这是declval

的文档

此解决方法适用于我:

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&>

答案 3 :(得分:1)

这个怎么样?这是std::declval之前使用的方法。

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;
}