Почему копия кандидата на вычет необходима в качестве отдельного руководства по вычету? - PullRequest
0 голосов
/ 11 мая 2018
template <typename T> struct A {
    A(T);
    A(const A&);
};

int main()
{
    A x(42); // #1
    A y = x; // #2
}

Как я понимаю, T для # 1 будет выведено с использованием неявного руководства по выводу генерируется из первого ctor. Затем x будет инициализирован с использованием этого ctor.

Для # 2, однако, T будет выведено с использованием кандидата на вычет при копировании (что, как я понимаю, является конкретным случаем руководства по вычету) (а затем y будет инициализировано с использованием 2-го ctor).

Почему T для # 2 не может быть выведено с помощью (неявного) руководства по выводу, сгенерированного из copy-ctor?

Полагаю, я просто не понимаю общей цели кандидата на вычет копий.

Ответы [ 2 ]

0 голосов
/ 12 мая 2018

Основная проблема заключается в том, что в общем случае вы не знаете, является ли что-то конструктором копирования / перемещения, пока не узнаете аргументы шаблона и не создадите экземпляр специализации, но для CTAD вы не знаете аргументы шаблона (дух) и должны идти одни заявления:

template<bool B, class T>
struct A {
   A(std::conditional_t<B, A, int>&); // copy ctor? maybe
   A(std::conditional_t<!B, A&&, char>); // move ctor?

   T t;
   // A(const A&); // implicitly declared? or not? 
                   // is this even the right signature? (depends on T)
   // A(A&&); // implicitly declared? or not?
};
A a = A<true, int>(); // deduce?

Кандидат на вычет копии работает вокруг этого, а также избегает тонкостей разрешения перегрузки, касающихся категории значений и квалификаций cv, используя параметр по значению.

0 голосов
/ 11 мая 2018

Первоначальный черновик для добавления формулировки для вычета при копировании был P0620R0 , в котором упоминается

Эта статья предназначена для разрешения

  • Направление обёртывания и копирования из EWG в понедельник в Kona

Некоторые заметки об этой встрече доступны на https://botondballo.wordpress.com/2017/03/27/trip-report-c-standards-meeting-in-kona-february-2017/:

Копирование и упаковка. Предположим, что a является переменной типа tuple<int, int>, и мы пишем tuple b{a};. Должен ли тип b быть tuple<int, int> (поведение "копирования") или tuple<tuple<int, int>> (поведение "упаковки")? Этот вопрос возникает для любого типа-обертки (такого как pair, tuple или optional), который имеет как конструктор копирования, так и конструктор, который принимает объект обертываемого типа. EWG чувствовал, что копирование было лучшим по умолчанию. Был некоторый разговор о том, чтобы сделать поведение зависимым от синтаксиса инициализации (например, синтаксис { } должен всегда переноситься), но EWG чувствовала, что введение новых несоответствий между поведениями различных синтаксисов инициализации принесет больше вреда, чем пользы.

@ kiloalphaindia объяснил это в комментарии :

Если # 2 будет использовать A::A(T), мы получим y beeing A<A<int>>. [...]

Это верно. Конструктор A<A<int>>::A(A<int>) имеет точное совпадение в типе параметра. С другой стороны, вы также правы, что вместо этого предпочтительным было бы A<int>::A(const A<int> &).

Но рассмотрим эту альтернативу, где эквивалент функции показывает, что A<A<int>> было бы предпочтительным, если бы не кандидат на вычет копии:

template <typename T>
struct A {
    A(T &&);
    A(const A<T> &);
};

template <typename T> auto f(T &&) -> A<T>;
template <typename T> auto f(const A<T> &) -> A<T>;

int main() {
  A x1(42);                   // A<int>
  A y1 = std::move(x1);       // A<int>

  auto x2 = f(42);            // A<int>
  auto y2 = f(std::move(x2)); // A<A<int>>
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...