I created a two classes - one can be converted to another by the conversion operator:
struct MyClass{};
struct MyClass2{
operator MyClass() const { return MyClass{}; }
};
and a specialised template function (specialisation for std::initializer_list<MyClass>
):
template<typename T>
void foo(std::initializer_list<T>)
{
}
template<>
void foo(std::initializer_list<MyClass>)
{
std::cout << "specialised template foo<>()";
}
When I try to call foo
with the initializer list mixing MyClass
and MyClass2
:
foo({MyClass{}, MyClass2{}, MyClass2{}});
compiler opposes (as I am mixing two different types):
<source>:35:8: error: no matching function for call to 'foo(<brace-enclosed initializer list>)'
35 | foo({MyClass{}, MyClass2{}, MyClass2{}});
| ~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:19:6: note: candidate: 'template<class T> void foo(std::initializer_list<_Tp>)'
19 | void foo(std::initializer_list<T>)
| ^~~
<source>:19:6: note: template argument deduction/substitution failed:
<source>:35:8: note: deduced conflicting types for parameter '_Tp' ('MyClass' and 'MyClass2')
35 | foo({MyClass{}, MyClass2{}, MyClass2{}});
| ~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
But from some reason if I add an non-template overload of foo
for the same type as in template specialisation - it works like a charm!
void foo(std::initializer_list<MyClass>)
{
std::cout << “overloaded foo()";
}
int main(int argc, char **argv) {
foo({MyClass{}, MyClass2{}, MyClass2{}}); // Program stdout : overloaded foo()
}
I guess that non-template overload has a priority over templates when compiler looks up for a function. But why it does work with overload and does not work with template specialisation? Is it undefined behaviour? Or is it completely legal to do it so?
Live example: https://godbolt.org/z/5ohhK1jeb
Aucun commentaire:
Enregistrer un commentaire