在C ++ 11中,有没有办法为lambda函数建立模板?还是固有地太具体而无法模板化?
我了解我可以改为定义经典的模板化类/函数,但问题更像是:该语言是否允许模板化lambda函数?
在C ++ 11中,有没有办法为lambda函数建立模板?还是固有地太具体而无法模板化?
我了解我可以改为定义经典的模板化类/函数,但问题更像是:该语言是否允许模板化lambda函数?
Answers:
更新2018:C ++ 20将带有模板化和概念化的lambda。该功能已集成到标准草稿中。
2014年更新:C ++ 14已于今年发布,现在为多态lambda提供与该示例相同的语法。一些主要的编译器已经实现了它。
就目前而言(在C ++ 11中),可惜没有。就灵活性和功能而言,多态lambda极佳。
他们最终变得单态的最初原因是由于概念。概念使此代码情况变得困难:
template <Constraint T>
void foo(T x)
{
auto bar = [](auto x){}; // imaginary syntax
}
在受限模板中,您只能调用其他受限模板。(否则无法检查约束。)可以foo
调用bar(x)
吗?lambda有什么约束(毕竟它的参数只是一个模板)?
概念还没有准备好解决这类问题。它需要更多的东西late_check
(例如,直到调用该概念才对其进行检查)和其他东西。更简单的是放弃所有内容并坚持使用单态lambda。
但是,随着C ++ 0x中概念的删除,多态lambda再次成为一个简单的命题。但是,我找不到任何建议。:(
C ++ 11 lambda无法像其他答案中所述进行模板化,但是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);
}
印刷品:
My string
1024
1
我发现该技术在使用模板化代码时很有用,但意识到它仍然意味着无法对lambda本身进行模板化。
T
可以代替decltype(t)
此示例。
在C ++ 11中,无法对lambda函数进行模板化,但是在下一个版本的ISO C ++ Standard(通常称为C ++ 14)中,将引入此功能。[资源]
用法示例:
auto get_container_size = [] (auto container) { return container.size(); };
请注意,尽管语法使用关键字auto
,但类型推导将不使用auto
类型推导的规则,而是使用模板参数推导的规则。另请参见有关通用lambda表达式的建议(以及对此的更新)。
auto
类型推导的规则被专门定义为与template
函数自变量推导的规则相同。
我不知道这是怎么回事:
template <class something>
inline std::function<void()> templateLamda() {
return [](){ std::cout << something.memberfunc() };
}
我使用了类似的代码来生成模板,并想知道编译器是否会优化“包装”功能。
看一下用于多态lambda的Boost.Phoenix:http : //www.boost.org/doc/libs/1_44_0/libs/spirit/phoenix/doc/html/index.html 不需要C ++ 0x方式 :)
有一个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);
}
);
哪里_widgets
是std::tuple< fusion::pair<Key_T, Widget_T>... >
我一直在使用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;
}
这是涉及将兰巴包在结构中的一种解决方案:
template <typename T>
struct LamT
{
static void Go()
{
auto lam = []()
{
T var;
std::cout << "lam, type = " << typeid(var).name() << std::endl;
};
lam();
}
};
使用方法:
LamT<int>::Go();
LamT<char>::Go();
#This prints
lam, type = i
lam, type = c
与此相关的主要问题(除了额外的输入)无法将结构定义嵌入另一个方法中,否则您会得到(gcc 4.9)
error: a template declaration cannot appear at block scope
我也尝试这样做:
template <typename T> using LamdaT = decltype(
[](void)
{
std::cout << "LambT type = " << typeid(T).name() << std::endl;
});
希望我可以像这样使用它:
LamdaT<int>();
LamdaT<char>();
但是我得到了编译器错误:
error: lambda-expression in unevaluated context
因此,这是行不通的……但是,即使它进行了编译,它的用途也很有限,因为我们仍然必须将“ using LamdaT”放在文件作用域中(因为它是模板),这有点违背了lambdas。
我不确定为什么没有其他人建议这样做,但是您可以编写一个返回lambda函数的模板化函数。以下解决了我的问题,是我进入此页面的原因:
template <typename DATUM>
std::function<double(DATUM)> makeUnweighted() {
return [](DATUM datum){return 1.0;};
}
现在,只要我想要一个具有给定类型参数的函数(例如std::string
),我就说
auto f = makeUnweighted<std::string>()
现在f("any string")
返回1.0
。
这就是我所说的“模板化lambda函数”的例子。(当某人不想对他们的数据进行加权时(不管他们的数据可能是什么),此特殊情况用于自动提供惰性加权功能。)