Подтвердить что ты не робот

Почему авто нельзя использовать для перегрузки функций?

Я понимаю, что использование 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.

Спасибо

4b9b3361

Ответ 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 заключается в том, чтобы разрешить общие лямбда, которые вы не могли сделать раньше, и я предполагаю, что любой синтаксис с использованием синтаксиса шаблона был бы уродливым.