4

Я пытаюсь понять P0091r3 (документ «шаблонный аргумент для шаблонов классов», который был принят в текущий проект стандарта C++, N4606).Вопросы о выводе аргумента шаблона шаблона в C++ 17

Я считаю, что я понимаю, как это работает в простейшем возможном случае, когда шаблон имяидентифицирует один шаблон:

template<class T> 
struct S { 
    S(T); 
    S(const std::vector<T>&); 
}; 

int main() 
{ 
    std::vector<int> v; 
    auto s = S(v); 
} 

S идентифицирует исходный шаблон, поэтому мы создаем фиктивный набор перегрузки, состоящий из

template<class T> void Sctor(T); 
template<class T> void Sctor(const std::vector<T>&); 

и выполнять разрешение перегрузки на фиктивном вызов

Sctor(v) 

, чтобы определить, что в этом случае мы хотим назвать фиктивный Sctor(const std::vector<T>&) [with T=int]. Это означает, что мы в конечном итоге вызываем S<int>::S(const std::vector<int>&), и все отлично работает.

Я не понимаю, как это должно работать при наличии частичной специализации.

template<class T> 
struct S { 
    S(T); 
}; 

template<class T> 
struct S<std::list<T>> { 
    S(const std::vector<T>&); 
}; 

int main() 
{ 
    std::vector<int> v; 
    auto s = S(v); 
} 

То, что мы интуитивно хотим здесь призыв к S<std::list<int>>::S(const std::vector<int>&). Это то, что мы действительно получаем? и где это указано?

В принципе я не интуитивно понять, что означает P0091r3 от «шаблона класса, назначенного шаблона имя-»: это значит основной шаблон, или же она включает в себя все частичные специализации и явные полные специализации, а?

(я тоже не понимаю, как изменения P0091r3, чтобы §7.1.6.2p2 не ломаются код, используя нагнетаемого учащемуся имя- S, таких как

template<class T> 
struct iterator { 
    iterator& operator++(int) { 
     iterator result = *this; // injected-class-name or placeholder? 
     //... 
    } 
}; 

, но это другой вопрос в целом.)


ли класс шаблон вычет и явные руководства дедукции поддерживаются в любой сохранившейся версии Clang или GCC (возможно под -f флага, как -fconcepts есть)? Если это так, я мог бы поиграть с некоторыми из этих примеров в реальной жизни и, возможно, прояснить половину своей путаницы.

+0

На данный момент ни один главный компилятор (возможно, никакой компилятор вообще) поддерживает вывод аргумента шаблона для конструкторов. Если я не ошибаюсь, возможно, есть филиал Clang, который использовался для сбора опыта реализации, но я даже не уверен, что он доступен в любом месте в Интернете. – Morwenn

ответ

1

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

Это, как говорится, я считаю, что цель из P0091 заключается в том, что частичные специализации не участвуют в выводе аргументов. Эта функция позволяет компилятору решить, что такое аргументы шаблона класса. Однако то, что выбирает частичную специализацию, - это те аргументы шаблона. Способом получения специализации S<std::list<T>> является использование std::list в списке аргументов шаблона S.

Если вы хотите, чтобы конкретный параметр использовал определенную специализацию, вы должны использовать руководство по вычету. В конце концов, это то, за что они нужны.

2

Это предложение несколько контузировано, но я думаю, что цель состоит в том, что рассматриваются только конструкторы шаблона первичного класса. Свидетельство этого является то, что новый [class.template.deduction] имеет:

  • For each constructor of the class template designated by the template-name, a function template with the following properties is a candidate: [...]

Если мы говорим о «» шаблоне класса, то это шаблон первичного класса, в частности, в качестве шаблона класса частичного специализации не найдены при поиске по имени ([temp.class.spec]/6). Это также означает, что поведение прототипа (см. Ниже), как представляется, ведет себя.

В рамках статьи частичные специализации шаблона шаблона рассматриваются в разделе «За и против неявных руководств по вычитанию», но из-за беспокойства, что конструкторы в шаблоне основного класса могут вызвать сложную (не-SFINAE) ошибку:

template<class T> struct X { 
    using ty = T::type; 
    static auto foo() { return typename T::type{} }; 
    X(ty); #1 
    X(decltype(foo())); #2 
    X(T); 
}; 
template<class T> 
struct X<T*> { 
    X(...); 
}; 
X x{(int *)0}; 

Ваш призыв к шаблонных класса частичной специализации конструкторам следует рассматривать на лице его разумно, но учтите, что это может привести к двусмысленности:

template<class T> struct Y { Y(T*); }; 
template<class T> struct Y<T*> { Y(T*); }; 
Y y{(int*) 0}; 

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

Если вы хотите попробовать прототип реализации, авторы опубликовали свою ветку clang on github: https://github.com/faisalv/clang/tree/clang-ctor-deduction.


Обсуждение в работе («Записка о инжектированных именах классов») указует на то, что нагнетаемый класс наименования имеют приоритет над именами шаблонов; добавлена ​​формулировка:

The template-name shall name a class template that is not an injected-class-name.

+0

Re injected-class-names: я видел это предложение, но все еще не мог понять, означает ли это: «Если * имя-шаблона * - это * впрыснутое-класс-имя *, программа плохо сформирована» или «Имя шаблона * *, за которым следует открытая скобка, никогда не интерпретируется как * injected-class-name *, или что-то. ... На самом деле, ваша интерпретация («Имя шаблона * * должно интерпретироваться как * injected-class-name *, когда это возможно») в точности противоположно моей! : P – Quuxplusone

+0

@Quuxplusone [temp.local]/1 перечисляет, когда имя введенного класса рассматривается как * template-name *. –

Смежные вопросы