Пакет параметров должен быть в конце списка параметров... когда и почему?
Я не понимаю, почему пакет параметров должен быть в конце списка параметров, если последний привязан к классу, в то время как ограничение ослабляется, если список параметров является частью объявления метода-члена.
Другими словами, этот компилирует:
class C {
template<typename T, typename... Args, typename S>
void fn() { }
};
Следующий не делает:
template<typename T, typename... Args, typename S>
class C { };
Почему первый случай считается правильным, а второй-нет?
Я имею в виду, если это юридический синтаксис, разве не должно быть так в обоих случаях?
Быть ясно, что реальная проблема заключается в том, что я определял класс, подобный следующему:
template<typename T, typename... Args, typename Allocator>
class C { };
Наличие типа распределителя в качестве последнего типа было бы оценено, но я могу как-то обойти его (в любом случае, если у вас есть предложение, которое ценится, возможно, ваши гораздо более элегантны, чем мои!!).
Тем не менее, я получил ошибку:
Пакет параметров 'Args' должен находиться в конце списка параметров шаблона
Итак, мне просто было любопытно полностью понять, почему это принимается в одних случаях, но не принимается в других.
Вот похожий вопрос, но он просто объясняет, как решить проблему, и это было мне совершенно ясно.
2 ответов:
Это допустимо для шаблонов функций, но только тогда, когда дедукция аргументов может помочь компилятору разрешить параметры шаблона, так как ваш пример шаблона функции практически бесполезен, потому что
template<typename T, typename... Args, typename S> void fn() { } int main() { fn<int, int, int>(); }Компилятор не может определить, какие параметры шаблона принадлежат пакету параметров, а какие-пакетуtest.cpp: In function 'int main()': test.cpp:2:32: error: no matching function for call to 'fn()' int main() { fn<int, int, int>(); } ^ test.cpp:1:57: note: candidate: template<class T, class ... Args, class S> void fn() template<typename T, typename... Args, typename S> void fn() { } ^ test.cpp:1:57: note: template argument deduction/substitution failed: test.cpp:2:32: note: couldn't deduce template parameter 'S' int main() { fn<int, int, int>(); }S. На самом деле, как указывает @T. C., Это должно быть синтаксической ошибкой, потому что шаблон функции, определенный таким образом, никогда не может быть создать экземпляр.Более полезным шаблоном функции было бы что-то вроде
template<typename T, typename... Args, typename S> void fn(S s) { }Поскольку теперь компилятор может однозначно сопоставить параметр функции
sс типом шаблонаS, с побочным эффектом, чтоSбудет всегда выводиться - все явные параметры шаблона после первого будут принадлежатьArgs.Ничего из этого не работает для (первичных) шаблонов классов, параметры не выводятся, и это явно запрещено:
Из черновика n4567
Http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4567.pdf
[темп.param] / 11
[...]Если шаблон - параметр шаблона или псевдонима первичного класса шаблон-это набор параметров шаблона, он должен быть последним шаблон-параметр .[...]
(если бы они были выведены, это было бы неоднозначно, как в Примере шаблона функции).
Первый из них не прав. Компилятор просто глючит и не смог его диагностировать. [темп.парам]/11:
Пакет параметров шаблона шаблона функции не должен следовать другим параметром шаблона, если этот параметр шаблона не может быть выводится из parameter-type-list шаблона функции или имеет аргумент по умолчанию (14.8.2).
Если тип функции
T(Args...)имеет значение для конечного пользователя, один из способов исправить это будет вместо этого следует использовать частичную специализацию:template<class F, class Alloc> class C; //undefined template<class T, class... Args, class Alloc> class C<T(Args...), Alloc> { // implementation };В зависимости от фактических требований, стирание типа распределителя также может быть полезно рассмотреть.
Comments