Эквивалентны ли обычные шаблонные функции сокращённым шаблонным функциям?

Рейтинг: 2Ответов: 2Опубликовано: 31.05.2023

Эквивалентны ли следующие записи? И можно ли использовать одно в объявлении, а другое - в определении?

void foo(auto x);

template<typename T>
void foo(T x);

Я хочу использовать первый краткий вариант в заголовках для пользователей, а второй - в реализации, чтобы можно было легко получить доступ к типу T без decltype. Легально ли это?

Ответы

▲ 3

Да, должны быть эквивалентны, судя по [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.

Но, ИМХО, это плохая идея. Намного удобнее, когда объявление и определение записаны одинаково - можно копипастить одно в другое, если нужно что-то поменять в них. И если кто-то будет искать определение в коде, ему тоже будет проще, если запись будет совпадать.

▲ 2

Технически вы правы и они эквивалентны (лучший вид правоты :)).

[dcl.fct]/18:

... 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. ...

Однако есть как минимум две проблемы, из-за которых я бы не рекомендовал одновременное использование разных видов шаблонных функций.

  1. С практической точки зрения, clang и msvc принимают следующий код, а gcc — нет.
void foo(auto);

template <typename T>
void foo(T) {}

int main() { 
    foo(42);
}

error: call of overloaded 'foo(int)' is ambiguous

  1. Это вряд ли будет исправлено, т.к. с большой вероятностью в указанном пункте стандарта имеется в виду не эквивалентность, а функциональная эквивалентность, что означает, что программа ill-formed, no diagnostic required.

[temp.over.link]/7:

... 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.

Это следует из следующих наблюдений.

  • В том же пункте, в котором говорится про эквивалентность, в примере используется функциональная эквивалентность.

[dcl.fct]/example-7:

...

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.