I have a question about a C++ operator overloading on template class and type which is not correctly resolved by Microsoft Visual C++ while it is accepted by gcc and clang (Linux and macOS).
I suspect that this is a bug in MSVC++ but I would like to get the advice of experts before reporting the bug, in case it could be the opposite (gcc and clang being wrong).
The idea is a template class which must be instantiated with some integer type. We want to define the addition with any other plain integer types, both ways (class + int and int + class).
The minimal code for which I can reproduce the issue is below:
#include <type_traits>
template <typename INT, typename std::enable_if<std::is_integral<INT>::value>::type* = nullptr>
class A
{
public:
template<typename INT2>
A operator+(INT2 x) const { return A(); }
};
template <typename INT1, typename INT2>
A<INT2> operator+(INT1 x1, A<INT2> x2) { return x2 + x1; }
int main(int argc, char* argv[])
{
typedef A<int> B;
B x, y;
y = x + 1; // ok everywhere
y = 1 + x; // VC++: error C2677: binary '+': no global operator found which takes type 'B' (or there is no acceptable conversion)
}
In the original code, there are SFINAE constructs everywhere to enforce type checking when necessary (including in the two "+" operators). I have removed all of them when they did not change the compilation error. Only the "enable_if" in the definition of class A is required. Without it, the code compiles ok with MSVC++.
Microsoft Visual Studio 2019, version 16.9.3.
What is wrong here? MSVC++ or gcc/clang?
Thanks for your advices.
If we're being pedantic, in C++17, non-type template arguments cannot have type void*, see [temp.param]/4.2:
A non-type template-parameter shall have one of the following (optionally cv-qualified) types:
. . .
— pointer to object or pointer to function,
. . .
(Note: it has been rectified in C++20).
So it seems something goes wrong in MSVC (the SFINAE succeeds in A itself but causes the lookup of the operator to fail). MSVC doesn't support C++20 fully yet, but it may still be worth reporting the issue.
For more portable code, use SFINAE based on int instead of void*:
template <typename INT, typename std::enable_if<std::is_integral<INT>::value, int>::type = 0>
class A {
. . .
This compiles OK in MSVC 16.9.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With