Разрешение перегрузки функции о initializer_list - PullRequest
4 голосов
/ 08 апреля 2019
#include <vector>
using namespace std;

class A
{
public:
    explicit A(const initializer_list<int> & a) {}
};
void func(const vector<int>& a)
{

}
void func(A a)
{

}
int main(void)
{
    func({ 1,2,3 });
}

Этот код не компилируется:

(19): ошибка C2668: 'func': неоднозначный вызов перегруженной функции

(13): примечание: может быть 'void func (A)'

(9): примечание: или 'void func (const std :: vector> &)' с [_Ty = INT] (19): примечание: при попытке сопоставить список аргументов '(список инициализатора)'

Обратите внимание, что я указал "явный" в конструкторе А.

На мой взгляд, func(A a) не следует рассматривать в качестве кандидата {1,2,3}. И на самом деле это не так. Если я удаляю func(const vector<int>& a), то код все равно не работает, вместо того, чтобы удалить неоднозначность.

Итак, в этом коде func(const vector<int>& a) является единственной вызываемой функцией для {1,2,3}, поэтому двусмысленности нет.

Мой вопрос ..

  1. Как процедуры разрешения перегрузки в C ++ приходят к выводу о "неоднозначности"?

  2. Почему C ++ просто не выбирает вызываемый?

Ответы [ 2 ]

1 голос
/ 08 апреля 2019

Я считаю, что лязг здесь правильный.Разрешение перегрузки в C ++ работает в три этапа: сначала создается набор функций-кандидатов, который представляет собой набор всех функций, на которые потенциально может ссылаться вызов (в основном, набор всех функций, которые распознает разрешение имен).Этот начальный набор функций-кандидатов затем сужается, чтобы получить набор жизнеспособных функций (набор функций, которые могут принимать вызов с заданными аргументами).Наконец, жизнеспособные функции ранжируются для определения наилучшей жизнеспособной функции.Эта наилучшая жизнеспособная функция и будет называться в конечном итоге.

С [over.match.viable] / 4

В-третьих, для F будетжизнеспособная функция, для каждого аргумента должна существовать неявная последовательность преобразования, которая преобразует этот аргумент в соответствующий параметр F.[…]

На основе [over.best.ics] / 6 , в частности

Когда тип параметра не является ссылкой,Последовательность неявного преобразования моделирует инициализацию копирования параметра из выражения аргумента.[…]

может показаться, что такой неявной последовательности преобразования для void func(A a) не существует из-за того, что необходимый конструктор помечен explicit (при инициализации копирования произойдет сбой).Следовательно, функция не является жизнеспособной функцией и больше не рассматривается для разрешения перегрузки, в результате чего void func(const vector<int>& a) остается единственным жизнеспособным кандидатом, то есть функцией, которая затем будет вызываться.

Кроме того, чисто наНа концептуальном уровне может показаться, что инициализация параметра copy-list-initialisation параметра может быть неверно сформирована только тогда, когда мы действительно знаем, какой параметр мы собираемся инициализировать, т. е. знаем, какая функция на самом деле будет вызываться.Если вызов набора перегрузки был бы недопустим в тот момент, когда есть единственный аргумент, который не является допустимым инициализатором для соответствующего параметра в каждой потенциальной функции-кандидате, тогда какой смысл перегрузки?Пока мы все еще работаем над выяснением, какую функцию вызывать, нет способа решить, будет ли инициализация неправильной или нет.Clang демонстрирует именно это поведение.Когда вы закомментируете перегрузку void func(const std::vector<int>& a), clang внезапно пожалуется, что вызов не сформирован…

попробуйте здесь

1 голос
/ 08 апреля 2019

explicit конструкторы не игнорируются при выполнении инициализации списка.Такие конструкторы всегда рассматриваются как жизнеспособные кандидаты на перегрузку.Что происходит, если система пытается вызвать конструктор explicit при инициализации copy-list (то есть: после разрешения перегрузки), то вы получите серьезную ошибку компиляции.

В вашем случае она никогда не получитэто далеко, потому что набор перегрузки неоднозначен.

explicit не означает «не существует, если вы пытаетесь конвертировать»;это означает «ошибка, если вы пытаетесь конвертировать».Смысл explicit состоит в том, чтобы заставить пользователя думать о том, какой тип он на самом деле хочет использовать.Это сделано для того, чтобы пользователь не мог написать код, который несколько двусмысленен для reader .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...