Эквивалентны ли обычные шаблонные функции сокращённым шаблонным функциям?
Эквивалентны ли следующие записи? И можно ли использовать одно в объявлении, а другое - в определении?
void foo(auto x);
template<typename T>
void foo(T x);
Я хочу использовать первый краткий вариант в заголовках для пользователей, а второй - в реализации, чтобы можно было легко получить доступ к типу T без decltype. Легально ли это?
Ответы (2 шт):
Да, должны быть эквивалентны, судя по [dcl.fct]/22:
An abbreviated function template is equivalent to a function template ([temp.fct]) whose template-parameter-list includes one invented type template-parameter for each generic parameter type placeholder of the function declaration, in order of appearance.
Но, ИМХО, это плохая идея. Намного удобнее, когда объявление и определение записаны одинаково - можно копипастить одно в другое, если нужно что-то поменять в них. И если кто-то будет искать определение в коде, ему тоже будет проще, если запись будет совпадать.
Технически вы правы и они эквивалентны (лучший вид правоты :)).
... An abbreviated function template is equivalent to a function template ([temp.fct]) whose template-parameter-list includes one invented type template-parameter for each generic parameter type placeholder of the function declaration, in order of appearance. ...
Однако есть как минимум две проблемы, из-за которых я бы не рекомендовал одновременное использование разных видов шаблонных функций.
- С практической точки зрения,
clangиmsvcпринимают следующий код, аgcc— нет.
void foo(auto);
template <typename T>
void foo(T) {}
int main() {
foo(42);
}
error: call of overloaded 'foo(int)' is ambiguous
- Это вряд ли будет исправлено, т.к. с большой вероятностью в указанном пункте стандарта имеется в виду не эквивалентность, а функциональная эквивалентность, что означает, что программа ill-formed, no diagnostic required.
... If the validity or meaning of the program depends on whether two constructs are equivalent, and they are functionally equivalent but not equivalent, the program is ill-formed, no diagnostic required.
Это следует из следующих наблюдений.
- В том же пункте, в котором говорится про эквивалентность, в примере используется функциональная эквивалентность.
...
These declarations are functionally equivalent (but not equivalent) to the following declarations.
...
- В P0717 обсуждался как раз ваш юзкейс и было принято решение отклонить его (подробнее про голосование см. пункт Require redeclarations to use consistent syntax в P0691).
There may occasionally be a desire to declare a function with one syntax for readability to their users and define it with a different syntax, but doing so requires understanding the details of an arcane token rewrite rule so we would not recommend it even to an expert user. As a consequence, we recommend removing this deviation from normal template rules and that the regular rule for C++ templates be used: all declarations of a function template must use the same syntax for dependent portions of a template, including in the specification of constraints on constrained function templates.
- В репозитории черновика стандарта открыты 2 issues, в которых предлагают исправить эту неточность (1 и 2).
Подробнее про историю, почему так могло произойти, вы можете почитать в ответе на аналогичный вопрос с enSO.