I came across a rather strange case of overload resolution today. I reduced it to the following:
struct S
{
S(int, int = 0);
};
class C
{
public:
template <typename... Args>
C(S, Args... args);
C(const C&) = delete;
};
int main()
{
C c({1, 2});
}
I fully expected C c({1, 2})
to match the first constructor of C
, with the number of variadic arguments being zero, and {1, 2}
being treated as an initializer list construction of an S
object.
However, I get a compiler error that indicates that instead, it matches the deleted copy constructor of C!
test.cpp: In function 'int main()':
test.cpp:17:15: error: use of deleted function 'C(const C &)'
test.cpp:12:5: error: declared here
I can sort of see how that might work - {1, 2}
can be construed as a valid initializer for C, with the 1
being an initializer for the S
(which is implicitly constructible from an int because the second argument of its constructor has a default value), and the 2
being a variadic argument... but I don't see why that would be a better match, especially seeing as the copy constructor in question is deleted.
Could someone please explain the overload resolution rules that are in play here, and say whether there is a workaround that does not involve mentioning the name of S in the constructor call?
EDIT: Since someone mentioned the snippet compiles with a different compiler, I should clarify that I got the above error with GCC 4.6.1.
EDIT 2: I simplified the snippet even further to get an even more disturbing failure:
struct S
{
S(int, int = 0);
};
struct C
{
C(S);
};
int main()
{
C c({1});
}
Errors:
test.cpp: In function 'int main()':
test.cpp:13:12: error: call of overloaded 'C(<brace-enclosed initializer list>)' is ambiguous
test.cpp:13:12: note: candidates are:
test.cpp:8:5: note: C::C(S)
test.cpp:6:8: note: constexpr C::C(const C&)
test.cpp:6:8: note: constexpr C::C(C&&)
And this time, GCC 4.5.1 gives the same error, too (minus the constexpr
s and the move constructor which it does not generate implicitly).
I find it very hard to believe that this is what the language designers intended...