Тип повернення лямбди може бути виведений за значенням, що повертається, то чому не може функція?


75
#include <iostream>

int main(){

    auto lambda = [] {
        return 7;
    };

    std::cout << lambda() << '\n';

}

Ця програма компілює та друкує 7.
Тип повернення лямбда виводиться до цілочисельного типу на основі поверненого значення 7.


Чому це неможливо зі звичайними функціями?

#include <iostream>

auto function(){
    return 42;
}

int main(){

    std::cout << function() << '\n';
}

помилка: функція "function" використовує специфікатор типу "auto" без кінцевого типу повернення


5
Вже доступний у VS2013 Nov CTP. Це вже доступна функція C ++ 14. Це надзвичайна допомога для шаблонованих функцій із безладними типами повернення.
CodeAngry

Відповіді:


77

C ++ 14 має цю функцію . Ви можете протестувати його в нових версіях GCC або clang, встановивши -std=c++1yпрапор.

Живий приклад

На додаток до цього, в C ++ 14 ви також можете використовувати decltype(auto)(що відображається decltype(auto)як змінні) для своєї функції, щоб визначити її повернене значення за допомогою decltypeсемантики.

Прикладом може бути той, що стосується функцій пересилання, для яких decltype(auto)особливо корисно:

template<typename function_type, typename... arg_types>
decltype(auto) do_nothing_but_forward(function_type func, arg_types&&... args) {
    return func(std::forward<arg_types>(args)...);
}

За допомогою decltype(auto), ви імітуєте фактичний тип повернення funcпри виклику із зазначеними аргументами. Більше не дублюється код у завершальному типі повернення, що дуже розчаровує та схильне до помилок у C ++ 11.


3
Чому decltype(auto)і не просто auto?
dashesy

25

Це лише обмеження того, як мову створювали та еволюціонували. У майбутньому стандарті C ++ 14 у деяких контекстах можна визначити тип повернення функції, хоча не у всіх. Існують ускладнення, коли є декілька операторів повернення.

Крім того, виведені типи повернення мають інші проблеми, наприклад, тип повернення функції шаблону не може використовуватися в контексті SFINAE , оскільки для можливості виведення типу компілятор повинен створити екземпляр шаблону функції, що трапляється після заміни. Кінцевий результат полягає в тому, що, хоча ця функція з’явиться найближчим часом, я б її уникнув, якщо ви зможете надати тип самі.


5
"Це лише обмеження того, як мову створювали та еволюціонували". - Звичайно, є, +1 лише для цього.
Крістіан Рау,



5

Я здогадуюсь, що це, мабуть, тому , що лямбди, виведені за типом, не можуть бути рекурсивними .

Чому це важливо? Оскільки, якщо виведена типом лямбда може бути рекурсивною (під "виведеною типом" я маю на увазі, де ім'я змінної має тип auto), то її тип повернення може потенційно залежати від нього самого, і хоча це іноді можливо вирішити, це набагато складніше у реалізації, ніж "простий" тип умовиводу. Я навіть не впевнений, чи завжди це можна вирішити (чи можна це вирішувати в загальному випадку?). Однак, якщо функції підтримували умовивід типу, слід було б подбати про цю проблему, тому цілком ймовірно, що вони просто виключили їх із цієї причини.


1
Ви можете пояснити більше?
Bryan Chen

1
Це не різниця між лямбдами та визначеннями функцій. Навіть прості об'єкти можуть вказати циклічну залежність, auto x = x * 2;. У всіх випадках це просто заборонено.
Potatoswatter

1
@Mehrdad Це заборонено. Те саме, що самореференційна лямбда. Це моя думка.
Potatoswatter

2
Лямбди та функції можуть бути рекурсивними, а ініціалізація змінних може бути самореференційною, але autoнеправильно сформована, якщо існує циклічна залежність.
Potatoswatter

2
У цій відповіді Ви стверджуєте, що рекурсія потенційно створює проблему у поєднанні з auto. Я відповідаю, що це правда, але вони вже вирішили проблему, просто заборонивши вам робити не те, що потрібно. Немає жодної причини, за якою функції повинні відрізнятися від лямбда, а в C ++ 14 вони не будуть.
Potatoswatter
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.