Подтвердить что ты не робот

Почему компилятор не может вывести параметр шаблона при использовании с оператором преобразования?

Рассмотрим следующий код:

#include <utility>

template<typename T>
struct wrapper {
    T value;
};

struct foo {
    operator wrapper<int>() {
        return{10};
    }
};


int main() {
    foo f;
    wrapper w = f; // error
    std::pair p = std::make_pair(1, 0); // ok
}

gcc 7.1.1 не удается скомпилировать на отмеченной строке выше:

main.cpp: In function 'int main()':
main.cpp:17:17: error: class template argument deduction failed:
     wrapper w = f; // error
                 ^
main.cpp:17:17: error: no matching function for call to 'wrapper(foo&)'
main.cpp:4:8: note: candidate: template<class T> wrapper(wrapper<T>)-> wrapper<T>
 struct wrapper {
        ^~~~~~~
main.cpp:4:8: note:   template argument deduction/substitution failed:
main.cpp:17:17: note:   'foo' is not derived from 'wrapper<T>'
     wrapper w = f; // error
                 ^

f конвертируется в wrapper<int>, поэтому я ожидаю, что это произойдет. Оттуда компилятор должен уметь вывести, что T есть int. Но он не может.

Компилятор может правильно определить параметр шаблона std::pair, поэтому мне интересно, почему это не так с wrapper.

Любые идеи?

4b9b3361

Ответ 1

Для вывода аргумента шаблона шаблона "набор перегрузки" составлен, как описано в [over.match.class.deduct/1], Это следующие:

Создан набор функций и шаблонов функций, содержащих:
(1.1) - для каждого конструктора шаблона основного класса, указанного по имени шаблона, если шаблон определен, шаблон функции со следующими свойствами:
(1.1.1). Параметры шаблона параметры шаблона шаблона класса, за которым следует шаблон параметры (включая аргументы шаблона по умолчанию) конструктора, если таковые имеются.
(1.1.2). Типы параметров функции - типы конструктор.
(1.1.3) - Тип возврата - шаблон класса специализация, назначенная аргументами шаблона-шаблона и шаблона соответствующие параметрам шаблона, полученным из класса шаблон.

(1.2) - Если шаблон основного класса C не определен или не объявлять любые конструкторы, дополнительный шаблон функции, полученный как выше из гипотетического конструктора C().

(1.3) - дополнительный шаблон функции, полученный, как указано выше, из гипотетический конструктор C (C), называемый кандидатом на копирование.

(1.4) - для каждого указателя вычетов шаблон функции или функции с следующие свойства:
(1.4.1). Параметры шаблона, если таковые имеются, и функциональные параметры являются параметрами руководства по вычитанию.
(1.4.2). Тип возврата - это простой шаблон-идентификатор руководства по вычитанию.

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

Причина, по которой она работает для std::pair, связана с пунктом 1.3 и "кандидатом на вывод на копирование", который он определяет.