Почему авто нельзя использовать для перегрузки функций?
Я понимаю, что использование templates
является одним из оцененных способов перегрузки, но мне было интересно, почему auto
нельзя использовать для вывода типа параметра функции, тем самым предотвращая перегрузку функции?
N3690
говорит в 7.6.1.4/3, что выражение лямбда можно сделать общим с использованием auto, предоставив этот пример
auto glambda = [](int i, auto a) { return i; };//OK: a generic lambda
(примечание: это не упоминается в N3485)
1). Почему бы мне не сделать аналогичную вещь для нормальной функции, например,
void swap(auto& param1, decltype(param1)& param2)
{
decltype(param1) temp = param1;
param1 = param2;
param2 = temp;
}
это дает ошибки error : parameters declared auto
.
от N3690 7.1.6.4/4
Тип переменной, объявленной с использованием auto или decltype (auto), выводится из инициализатор. Это использование разрешено при объявлении переменных в блоке (6.3), в области пространства имен (3.3.6) и в for-init-statement (6.5.3). [...]
Я ошибаюсь, полагая, что param1
и param2
попадают под область блока и, следовательно, имеют право на автоматический вывод?
2). если такая возможность была разрешена, то что было бы ошибкой?
Я использую gcc 4.8.1.
Спасибо
Ответы
Ответ 1
n3690 7.1.6.4/2
Тип-заполнитель может появиться с объявлением функции в объявлении-specifier-seq, type-specifier-seq,
convert-function-id или trailing-return-type, в любом контексте, где такой декларатор действителен.
7.1.6.4/3
Если автоматический тип-спецификатор появляется как один из спецификаторов-деклараторов в определении-specifier-seq параметра-
объявление лямбда-выражения, лямбда - это общая лямбда.
7.1.6.4/4
Тип переменной, объявленной с использованием auto или decltype (auto), выводится из его инициализатора. Это использование аль-
при объявлении переменных в блоке (6.3), в области пространства имен (3.3.6) и в for-init-statement (6.5.3).
auto или decltype (auto) должны отображаться как один из спецификаторов decl в spec-specifier-seq, а decl-
за спецификатором-seq следует один или несколько init-деклараторов, каждый из которых должен иметь непустую начальную строку,
Izer.
7.1.6.4/5
Тип заполнителя также может использоваться при объявлении переменной в условии оператора выбора (6.4) или
(6.5), в типе-спецификаторе-seq в идентификаторе нового типа или типе-идентификатора нового выражения (5.3.4), в
декларацию for-range и объявление статического элемента данных с появлением символа скобки или равенства
в рамках спецификации элемента определения класса (9.4.2).
Оказывается только такое использование. Любое другое использование запрещено (в частности, использование в parameter-declaration-clause
).
7.1.6.4/6
Программа, которая использует auto или decltype (auto) в контексте, явно не разрешенном в этом разделе, плохо сформирована.
Ответ 2
N3690 - это проект комитета для С++ 14, т.е. для следующего стандарта С++, который еще не выпущен и который еще не может быть реализован в большинстве компиляторов. Поэтому вы должны ссылаться на свою компиляторную документацию, если реализованы универсальные лямбда - я думаю, что это не так.
Однако с gcc у вас есть хорошие шансы, что функции С++ 14 будут реализованы до официального выпуска нового стандарта, хотя вам, возможно, придется явно включить поддержку С++ 14 с флагом командной строки. Глядя на документы, это должно быть -std=gnu++1y
В соответствии с этот сайт, общие лямбды еще не реализованы в GCC.
Update:
Что касается обычных общих функций с использованием параметров auto
: они не существуют и не будут появляться в следующий раз. Причина в том, что шаблонные функции лишь немного более подробные для типа и более мощные, поскольку вы можете ссылаться на типы и напрямую применять метафоры шаблонов к ним. В generic lambdas это можно сделать только с помощью decltype(a)
, который немного более утомителен и должен использоваться с осторожностью, потому что он ведет себя немного иначе, чем дефолт аргумента шаблона.
Дополнительный бонус с шаблонами по сравнению с автоматическими параметрами - это немного больше типов или выразительности:
void func(auto a, auto b); //a and b might be different types
template <class T>
void func(T a, T b); //a and b must be the same type
Ответ 3
В верхней части ForEveR answer:
Почему я не могу сделать подобную вещь для нормальной функции, например,
void swap(auto& param1, decltype(param1)& param2)
Просто потому, что язык этого не позволяет. До того, как auto
был (повторно) изобретен в С++ 11, то, что вы хотите, было доступно через шаблоны:
template <class T, class U>
void swap(T& param1, U& param2);
С++ 11 также с помощью лямбда-выражений и С++ 14, вероятно, введут полиморфные лямбда, которые, в основном, лямбда, чьи operator ()
являются шаблонами. Например, для полиморфных лямбдов рассматривался синтаксис, подобный синтаксису (например, взятый из N3418)
[]<class T>(T* p) { /* ... */ }
В конце предпочтительный синтаксис использовал auto
вместо введения списка параметров шаблона.
Верно, что можно рассмотреть вопрос о расширении этого синтаксиса синтаксиса для функциональных шаблонов (как предполагает OP), но, насколько я знаю, комитет не рассмотрел эту возможность. Это может произойти в будущем, но кто-то должен официально предложить его. Это может быть "приятной особенностью", но IMHO это просто синтаксический сахар, который не приносит большого значения языку.
Кроме того, я не вижу, как этот синтаксис синтаксиса (без списков параметров шаблонов) может использоваться для классов шаблонов и, возможно, расходятся синтаксис для функций шаблона от шаблонов классов, не стоит делать.
Ответ 4
Уже есть способ написать то, что вы хотели: -
template <class T>
void swap(T& param1, T& param2)
{
T temp = param1;
param1 = param2;
param2 = temp;
}
Итак, зачем создавать новый синтаксис, который не позволяет делать то, что вы не могли сделать раньше. Предлагаемое изменение lambdas заключается в том, чтобы разрешить общие лямбда, которые вы не могли сделать раньше, и я предполагаю, что любой синтаксис с использованием синтаксиса шаблона был бы уродливым.