Я пытаюсь понять, как правила выбора перегрузки приводят к следующему (неинтуитивному) поведению. Когда у меня есть следующие функции:
#include <iostream>
// Overload 1
template<class T>
void write(T data)
{
std::cout << "Called write(T data)" << std::endl;
}
// Overload 2
template<class T, class ...U>
void write(T&& obj, U&&... objs)
{
std::cout << "Called write(T&& obj, U&&... objs)" << std::endl;
}
int main(int, char**)
{
int j = 0;
write(j);
return 0;
}
void write(T data)
перегрузка void write(T data)
Перегрузка 1). Я думаю, что это имеет смысл для меня: кандидаты на выбор перегрузки являются void write<T>(T)
T = int
и void write<T,U>(T&)
T = int, U = <>
. И write(T)
и write(T&)
были бы одинаково специализированными, но Overload 2 имеет пустой пакет параметров, поэтому выбирается Overload 1. Однако, если добавить третью перегрузку:
#include <iostream>
// Overload 0
void write(const int& data)
{
std::cout << "Called write(const int& data)" << std::endl;
}
// Overload 1
template<class T>
void write(T data)
{
std::cout << "Called write(T data)" << std::endl;
}
// Overload 2
template<class T, class ...U>
void write(T&& obj, U&&... objs)
{
std::cout << "Called write(T&& obj, U&&... objs)" << std::endl;
}
int main(int, char**)
{
int j = 0;
write(j);
return 0;
}
Затем внезапно появляется void write(T&& obj, U&&... objs)
(перегрузка 2). Почему добавление перегрузки, которая не выбрана, изменяется, какая перегрузка действительно выбрана?
Если единственные кандидаты были void write<T,U>(T&)
T = int, U = <>
и void write(const int&)
Я понимаю, почему выбрана void write<T,U>(T&)
, поэтому, возможно, что-то о добавлении дополнительной перегрузки предотвращает участие void write(T data)
от выбора перегрузки? Если да, то почему?
Поскольку это, похоже, специфическое поведение компилятора, это наблюдалось на gcc 7.3.0.
Еще одно интересное поведение: если функции переупорядочиваются таким образом, что новая перегрузка помещается между исходными двумя (то есть Overload 1, Overload 0, Overload 2), то gcc отклоняет ее с call of overloaded 'write(int&) is ambiguous
. Если функции переупорядочиваются так, что последняя перегрузка является последней (то есть перегрузка 1, затем перегрузка 2, затем перегрузка 0), то write(const int& data)
выбрана.