C++ 可以模板化 lambda 函数吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3575901/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 13:10:17  来源:igfitidea点击:

Can lambda functions be templated?

c++templateslambdac++11

提问by Klaim

In C++11, is there a way to template a lambda function? Or is it inherently too specific to be templated?

在 C++11 中,有没有办法模板化 lambda 函数?或者它本质上太具体而无法模板化?

I understand that I can define a classic templated class/functor instead, but the question is more like: does the language allow templating lambda functions?

我知道我可以定义一个经典的模板化类/函子,但问题更像是:该语言是否允许模板化 lambda 函数?

采纳答案by GManNickG

UPDATE 2018: C++20 will come with templated and conceptualized lambdas. The feature has already been integrated into the standard draft.

2018 年更新:C++20 将带有模板化和概念化的 lambdas。该功能已集成到标准草案中。



UPDATE 2014: C++14 has been released this year and now provides Polymorphic lambdas with the same syntax as in this example. Some major compilers already implement it.

2014 年更新:C++14 已于今年发布,现在提供与此示例中语法相同的多态 lambda。一些主要的编译器已经实现了它。



At it stands (in C++11), sadly no. Polymorphic lambdas would be excellent in terms of flexibility and power.

目前(在 C++11 中),遗憾的是没有。多态 lambda 在灵活性和功能方面非常出色。

The original reason they ended up being monomorphic was because of concepts. Concepts made this code situation difficult:

他们最终成为单态的最初原因是因为概念。概念使这种代码情况变得困难:

template <Constraint T>
void foo(T x)
{
    auto bar = [](auto x){}; // imaginary syntax
}

In a constrained template you can only call other constrained templates. (Otherwise the constraints couldn't be checked.) Can fooinvoke bar(x)? What constraints does the lambda have (the parameter for it is just a template, after all)?

在受约束的模板中,您只能调用其他受约束的模板。(否则无法检查约束。)可以foo调用bar(x)? lambda 有什么约束(毕竟它的参数只是一个模板)?

Concepts weren't ready to tackle this sort of thing; it'd require more stuff like late_check(where the concept wasn't checked until invoked) and stuff. Simpler was just to drop it all and stick to monomorphic lambdas.

概念还没有准备好解决这类事情;它需要更多的东西,比如late_check(在调用之前不检查概念)和东西。更简单的方法是放弃所有内容并坚持使用单态 lambda。

However, with the removal of concepts from C++0x, polymorphic lambdas become a simple proposition again. However, I can't find any proposals for it. :(

然而,随着 C++0x 中概念的删除,多态 lambda 再次成为一个简单的命题。但是,我找不到任何建议。:(

回答by Joel

C++11 lambdas can't be templated as stated in other answers but decltype()seems to help when using a lambda within a templated class or function.

C++11 lambdas 不能像其他答案中所述那样被模板化,但decltype()在模板化类或函数中使用 lambda 时似乎有帮助。

#include <iostream>
#include <string>

using namespace std;

template<typename T>
void boring_template_fn(T t){
    auto identity = [](decltype(t) t){ return t;};
    std::cout << identity(t) << std::endl;
}

int main(int argc, char *argv[]) {
    std::string s("My string");
    boring_template_fn(s);
    boring_template_fn(1024);
    boring_template_fn(true);
}

Prints:

印刷:

My string
1024
1

I've found this technique is helps when working with templated code but realize it still means lambdas themselves can't be templated.

我发现这种技术在使用模板化代码时很有帮助,但意识到它仍然意味着 lambdas 本身不能被模板化。

回答by Timo Türschmann

In C++11, lambda functions can not be templated, but in the next version of the ISO C++ Standard (often called C++14), this feature will be introduced.[Source]

在 C++11 中,无法对 lambda 函数进行模板化,但在下一版本的 ISO C++ 标准(通常称为 C++14)中,将引入此功能。[来源]

Usage example:

用法示例:

auto get_container_size = [] (auto container) { return container.size(); };

Note that though the syntax uses the keyword auto, the type deduction will not use the rules of autotype deduction, but instead use the rules of template argument deduction. Also see the proposal for generic lambda expressions(and the updateto this).

请注意,虽然语法使用了关键字auto,但类型推导不会使用auto类型推导规则,而是使用模板参数推导规则。另请参阅通用 lambda 表达式提案(以及对此的更新)。

回答by Ram

I am aware that this question is about C++11. However, for those who googled and landed on this page, templated lambdas are now supported in C++14 and go by the name Generic Lambdas.

我知道这个问题是关于 C++11 的。但是,对于那些在 google 上搜索并登陆此页面的人来说,C++14 现在支持模板化 lambdas,名称为 Generic Lambdas。

[info] Most of the popular compilers support this feature now. Microsoft Visual Studio 2015 supports. Clang supports. GCC supports.

[信息] 现在大多数流行的编译器都支持此功能。Microsoft Visual Studio 2015 支持。Clang 支持。海湾合作委员会支持。

回答by ted

I wonder what about this:

我想知道这个怎么办:

template <class something>
inline std::function<void()> templateLamda() {
  return [](){ std::cout << something.memberfunc() };
}

I used similar code like this, to generate a template and wonder if the compiler will optimize the "wrapping" function out.

我使用类似这样的代码来生成模板,并想知道编译器是否会优化“包装”功能。

回答by usta

Have a look at Boost.Phoenix for polymorphic lambdas: http://www.boost.org/doc/libs/1_44_0/libs/spirit/phoenix/doc/html/index.htmlDoes not require C++0x, by the way :)

看看 Boost.Phoenix 的多态 lambda:http: //www.boost.org/doc/libs/1_44_0/libs/spirit/phoenix/doc/html/index.html不需要 C++0x,由道路 :)

回答by user6559931

There is a gcc extensionwhich allows lambda templates:

有一个gcc 扩展允许使用lambda 模板

// create the widgets and set the label
base::for_each(_widgets, [] <typename Key_T, typename Widget_T>
                         (boost::fusion::pair<Key_T, Widget_T*>& pair) -> void {
                             pair.second = new Widget_T();
                             pair.second->set_label_str(Key_T::label);
                          }
              );

where _widgetsis a std::tuple< fusion::pair<Key_T, Widget_T>... >

哪里_widgetsstd::tuple< fusion::pair<Key_T, Widget_T>... >

回答by Doug Coburn

I've been playing with the latest clang version 5.0.1compiling with the -std=c++17flag and there is now some nice support for auto type parameters for lambdas:

我一直在玩最新的version 5.0.1带有-std=c++17标志的clang编译,现在对 lambda 的自动类型参数有一些很好的支持:

#include <iostream>
#include <vector>
#include <stdexcept>

int main() {
    auto slice = [](auto input, int beg, int end) {
        using T = decltype(input);
        const auto size = input.size();
        if (beg > size || end > size || beg < 0 || end < 0) {
            throw std::out_of_range("beg/end must be between [0, input.size())");
        }
        if (beg > end) {
            throw std::invalid_argument("beg must be less than end");
        }
        return T(input.begin() + beg, input.begin() + end);
    };
    auto v = std::vector<int> { 1,2,3,4,5 };
    for (auto e : slice(v, 1, 4)) {
        std::cout << e << " ";
    }
    std::cout << std::endl;
}

回答by rmccabe3701

Here is one solution that involves wrapping the lamba in a structure:

这是一种涉及将 Lamba 包装在结构中的解决方案:

template <typename T>                                                   
struct LamT                                                             
{                                                                       
   static void Go()                                                     
   {                                                                    
      auto lam = []()                                                   
      {                                                                 
         T var;                                                         
         std::cout << "lam, type = " << typeid(var).name() << std::endl;
      };                                                                

      lam();                                                            
   }                                                                    
};   

To use do:

要使用做:

LamT<int>::Go();  
LamT<char>::Go(); 
#This prints 
lam, type = i
lam, type = c

The main issue with this (besides the extra typing) you cannot embed this structure definition inside another method or you get (gcc 4.9)

与此有关的主要问题(除了额外的打字)您不能将此结构定义嵌入另一个方法中,否则您会得到(gcc 4.9)

error: a template declaration cannot appear at block scope

I also tried doing this:

我也试过这样做:

template <typename T> using LamdaT = decltype(                          
   [](void)                                                          
   {                                                                 
       std::cout << "LambT type = " << typeid(T).name() << std::endl;  
   });

With the hope that I could use it like this:

希望我可以像这样使用它:

LamdaT<int>();      
LamdaT<char>();

But I get the compiler error:

但我收到编译器错误:

error: lambda-expression in unevaluated context

So this doesn't work ... but even if it did compile it would be of limited use because we would still have to put the "using LamdaT" at file scope (because it is a template) which sort of defeats the purpose of lambdas.

所以这不起作用......但即使它确实编译了它也会有有限的用途,因为我们仍然必须将“使用LamdaT”放在文件范围内(因为它是一个模板)这有点违背了目的拉姆达。

回答by Jim Pivarski

I'm not sure why nobody else has suggested this, but you can write a templated function that returns lambda functions. The following solved my problem, the reason I came to this page:

我不确定为什么没有其他人建议这样做,但是您可以编写一个返回 lambda 函数的模板化函数。以下解决了我的问题,我来到这个页面的原因:

template <typename DATUM>
std::function<double(DATUM)> makeUnweighted() {
  return [](DATUM datum){return 1.0;};
}

Now whenever I want a function that takes a given type of argument (e.g. std::string), I just say

现在每当我想要一个接受给定类型参数(例如std::string)的函数时,我就说

auto f = makeUnweighted<std::string>()

and now f("any string")returns 1.0.

现在f("any string")返回1.0

That's an example of what I mean by "templated lambda function." (This particular case is used to automatically provide an inert weighting function when somebody doesn't want to weight their data, whatever their data might be.)

这是我所说的“模板化 lambda 函数”的一个例子。(当有人不想对他们的数据进行加权时,无论他们的数据是什么,这种特殊情况用于自动提供一个惰性加权函数。)