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
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;
}
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.
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.
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, ...)
{
}