SFINAE check for operator+=

前端 未结 4 557
无人共我
无人共我 2021-01-01 21: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 :

t         


        
相关标签:
4条回答
  • 2021-01-01 21:31

    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;
    }
    
    0 讨论(0)
  • 2021-01-01 21:38

    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.

    0 讨论(0)
  • 2021-01-01 21:42

    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.

    0 讨论(0)
  • 2021-01-01 21:54

    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, ...)
    {
    }
    
    0 讨论(0)
提交回复
热议问题