【问题标题】:Using template parameter in a generic lambda在通用 lambda 中使用模板参数
【发布时间】:2014-12-13 15:06:13
【问题描述】:

GCC 允许以下语法作为扩展名:

// a functional object that will add two like-type objects
auto add = [] <typename T> (T a, T b) { return a + b; };

n3418,2012 年通用 lambda 提案中,我们看到了允许上述情况的语法:

overload( []<class T>(T* p) {...},

但是,由于它是一个扩展,语法显然不存在(或不允许)。在什么情况下,当我们有 auto 时,上面的语法会有用,为什么语法不存在(或不允许)?

【问题讨论】:

    标签: c++ lambda c++14 c++20


    【解决方案1】:

    在我看来,C++14 的多态 lambda 更简洁。

    您可以重现您的示例情况的效果,如下所示:

    struct A {};
    struct B {};
    
    int operator+(A, A) { return 1; }
    int operator+(B, B) { return 2; }
    int operator+(A, B) { return 3; }
    int operator+(B, A) { return 4; }
    
    int main() {
        auto add = [](auto a, decltype(a) b) { return a + b; };
        auto flexible_add = [](auto a, auto b) { return a + b; };
    
        add(A{}, A{});  // works
        add(B{}, B{});  // works
        add(A{}, B{});  // doesn't work
    
        flexible_add(A{}, A{});  // works
        flexible_add(B{}, B{});  // works
        flexible_add(A{}, B{});  // works
    
        auto deref = [](auto *a) { return *a; };
        int foo{};
        A a;
        B b;
        deref(&foo); // works
        deref(&a);   // works
        deref(&b);   // works
        deref(foo);  // doesn't work
        deref(a);    // doesn't work
        deref(b);    // doesn't work
    }
    

    尽管在许多情况下 GCC 扩展功能更强大,不仅在您的用例中(它更自然地适合)。例如,关于非类型模板参数:

    #include <cstddef>
    #include <utility>
    #include <iostream>
    
    void print(std::initializer_list<std::size_t> il)
    {
        for (auto&& elem : il) std::cout << elem << std::endl;
    }
    
    int main()
    {
        auto indexed_lambda = [] <std::size_t... Is> (std::index_sequence<Is...>) { print({Is...}); };
    
        indexed_lambda(std::make_index_sequence<5>{});    
    }
    

    Coliru

    复杂的泛型参数类型:

    void foo() {}
    
    int main() {
        auto accept_no_args_fun_only = [] <typename R> (R (*)()) {};
    
        accept_no_args_fun_only(foo);
    }
    

    Coliru

    可变参数:

    #include <tuple>
    #include <vector>
    
    int main() {
        auto accept_vector = [] (std::vector<auto> &&) {}; // Unconstrained placeholder from Concept TS, but not variadic
        auto accept_tuple = [] <typename... Args> (std::tuple<Args...> &&) {};
    
        accept_vector(std::vector{42});
        accept_tuple(std::tuple{42});
    }
    

    Coliru

    我不知道涉及包含通用 lambda 的讨论,但我可以看到有人在思考这样的扩展是否值得包含,当当前语法涵盖大多数用例、简洁且适合 lambda 的意图时,最常见的是用于生成简短的 sn-ps 代码。

    编辑

    GCC 扩展已决定在the first C++20 ISO standards meeting 上成为 C++ 的一部分:

    【讨论】:

    • 所以把this code翻译成你的更灵活的lambdas
    • 我只是想指出通用 lambda 不支持的情况
    • 我认为您的示例与可变参数模板无关,而是与非类型模板参数有关。
    • @NirFriedman 我根本不明白你的意思。非类型模板参数和可变参数模板不是相互排斥的,示例同时使用了两者。请注意,我不是结尾示例的原作者,它是从 Piotr 的建议中逐字复制的,我已经嵌入了该建议,因为我确实看到了相关性。
    • @NirFriedman 我添加了一个最终编辑,将整个答案重新措辞,以便在此讨论中嵌入信息和示例。希望它不再误导。
    猜你喜欢
    • 2021-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-07
    • 2018-06-02
    相关资源
    最近更新 更多