之间有什么区别
template <typename T> void func( T t ) { /* ... */ }
和使用带有自动参数的lambdas的C ++ 14替代方案?
auto func = []( auto t ) { /* ... */ }
哪一个应该首选?
答案 0 :(得分:8)
不同之处在于,第一个是功能模板,您必须在使用之前定义它;一旦定义在那里,任何人都可以使用它。所以它是一个可重用的代码片段,永远存在。
另一方面,Lambdas非常方便:您可以在需要时定义它。如果lambda在函数内部定义为本地对象,则只有该函数可以使用它并将其传递给其他函数。它仍然是可重用的,但不如功能模板。但是,在命名空间级别定义的lambda与函数模板一样可重用,因为任何人都可以使用它。因此,在命名空间级别定义它时,它与函数模板没有太大区别。专家可能会发现一些极端情况。一个这样的情况是,你可以专门化功能模板://specialization : possible only in case of template!
template<> void func(MyClass obj) { /* ... */ }
你不能用lambdas做到这一点!
答案 1 :(得分:7)
第一个是功能模板。它可以是专用的和重载的。它可以通过ADL找到。如果要获取地址,则必须明确地为其提供模板参数,或者在编译器可以推导出它们的上下文中执行此操作。
第二个,假设它出现在命名空间范围内,是一个带有模板化函数调用操作符的全局对象。它不能专门化或过载(全局变量与函数冲突,它们不会使它们超载)。 ADL无法找到它(ADL只能找到函数和函数模板)。如果在其上使用地址运算符,则会获得对象的地址,这是非常无用的。如果编译器可以推导出参数,则可以将对象本身转换为函数指针;你不能明确地提供它们。
你可以随意使用;只要知道任何一种选择的优点和缺点。我会推荐第一个。第二个的唯一优势就是它的简洁性,我希望在不久的将来我们也能为函数模板提供简洁的语法。
auto func(auto t) { ... }
答案 2 :(得分:2)
N3337,[expr.prim.lambda] / 3:
lambda表达式的类型(也是表达式的类型) closure object)是一个唯一的,未命名的nonunion类类型 - 称为 闭包类型 - 其属性如下所述。这个类类型 不是聚合(8.5.1)。闭包类型在。中声明 包含的最小块范围,类范围或命名空间范围 相应的lambda表达式。
这种闭包类型将保持一个类。但是它的重载函数调用操作符将是操作符函数模板,允许不同的特化。此外,与函数模板不同,您可以隐式地将闭包对象转换为函数指针。它真的很方便,不是吗? 引用N3559,它看起来像这样:
对于通用lambda L:
int(*fp)(int, char) = [](auto a, auto b){return a+b;};
闭包类型是
struct/*anonymous*/
{
template<class A,class B>
auto operator()(A a,B b) const
{
return a+b;
}
private:
template<class A,class B>
static auto __invoke(A a,B b)
{
return a+b;
}
template<class A,class B,class R>
using fptr_t = R(*)(A,B);
public:
template<class A,class B,class R>
operator fptr_t<R,A,B>() const
{
return &__invoke<A,B>; // Fixed that manually, they forgot to qualify the template name
}
} L;
int(*fp)(int,char) = L;
(将执行通常的模板参数推断)