SFINAE check for operator+=

浪尽此生 提交于 2019-12-30 03:59:07

问题


I'm trying to eliminate an overload from an overload set if operator+= is missing.

I know how to check if T+T is legal :

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

but this doesn't work for +=

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

Is this fixable by using another expression inside decltype or do I need another SFINAE construct?

The reason I need this eliminated from the overload set is that it clashes with another overload that accepts a functor to be used as an alternative to +=. Compilers are VS2013, gcc4.8


回答1:


I would write the second form as:

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

The deduced type for decltype(a+=b, void()) would be just void if the expression a+=b is valid, else it would result in SFINAE.

Well, even in the first form, I would use the trailing-return type approach.




回答2:


You need an lvalue on the left hand side of += but your solution has an xvalue. As dyp has stated in the comments, you can use declval<T&> to get an lvalue. This works fine (just tested it):

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



回答3:


How about this? it's the method used before 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;
}



回答4:


Adding this main() function:

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

This is what the compiler error is:

 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>())>

The key line is using xvalue (rvalue reference) as lvalue

This is the documentation for declval

This workaround works for me:

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

outputs 3

You can also use declval<T&> of course.



来源:https://stackoverflow.com/questions/26139083/sfinae-check-for-operator

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!