Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 模板函数与带自动参数的命名lambda_C++_Templates_Lambda_C++14_Generic Lambda - Fatal编程技术网

C++ 模板函数与带自动参数的命名lambda

C++ 模板函数与带自动参数的命名lambda,c++,templates,lambda,c++14,generic-lambda,C++,Templates,Lambda,C++14,Generic Lambda,两者的区别是什么 template <typename T> void func( T t ) { /* ... */ } 应该优先选择哪一个?区别在于第一个是功能模板,在使用之前必须定义它;一旦定义存在,任何人都可以使用它。因此,它是一段可重用的代码,并且永远存在 另一方面,lambda很方便:您可以在需要时定义它。如果lambda在函数内部定义为本地对象,则只有该函数才能使用它并将其传递给其他函数。它仍然是可重用的,但比函数模板少。然而,在名称空间级别定义的lambdas与函数

两者的区别是什么

template <typename T> void func( T t ) { /* ... */ }

应该优先选择哪一个?

区别在于第一个是功能模板,在使用之前必须定义它;一旦定义存在,任何人都可以使用它。因此,它是一段可重用的代码,并且永远存在

另一方面,lambda很方便:您可以在需要时定义它。如果lambda在函数内部定义为本地对象,则只有该函数才能使用它并将其传递给其他函数。它仍然是可重用的,但比函数模板少。然而,在名称空间级别定义的lambdas与函数模板一样可重用,因为任何人都可以使用它。所以,当您在名称空间级别定义函数模板时,它和函数模板并没有太大区别。专家们可能会发现一些角落案例。一种情况是,您可以专门化函数模板:

//specialization : possible only in case of template!
template<> void func(MyClass obj) { /* ... */ }
//专门化:仅在模板的情况下才可能!
模板void func(MyClass obj){/*…*/}

你不能用lambdas做这个

N3337,[expr.prim.lambda]/3:

lambda表达式的类型(也是 闭包对象)是一种唯一的、未命名的非统一类类型,称为 闭包类型-其属性如下所述。这类类型 不是骨料(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;
struct/*匿名*/
{
模板
自动运算符()(A,B)常量
{
返回a+b;
}
私人:
模板
静态自动调用(A,B)
{
返回a+b;
}
模板
使用fptr_t=R(*)(A,B);
公众:
模板
运算符fptr_t()常量
{
return&_invoke;//修复了手动操作时忘记限定模板名称的问题
}
}L;
int(*fp)(int,char)=L;

(将执行通常的模板参数推断)

第一个是函数模板。它可以是专用的和重载的。可以通过ADL找到它。当您想要获取地址时,您必须显式地为其提供模板参数,或者在编译器可以推断它们的上下文中执行

第二个,假设它出现在名称空间范围中,是一个带有模板化函数调用操作符的全局对象。它不能被专门化或重载(全局变量与函数冲突,它们不会重载)。ADL无法找到它(ADL仅查找函数和函数模板)。如果在上面使用address操作符,就可以得到对象的地址,这是非常无用的。如果编译器可以推断参数,对象本身可以转换为函数指针;您不能明确地提供它们

你想用什么就用什么;只是要意识到任何一种选择的优点和缺点。我推荐第一种。第二种方法的唯一优点是简洁,我希望在不久的将来,我们也能为函数模板提供简洁的语法

auto func(auto t) { ... }

你不能在C++14中使用
auto t
作为参数,这是合法的。很高兴知道在C++14中会发生这种情况。是的,它非常有用。重载需要与你谈谈。你可以通过以下方式专门化typedef decltype([](auto t){/*…/})Lambda;结构:Lambda{using Lambda::operator();void operator()(MyClass obj){/..*/}}func;如果你真的想的话。@RalphTandetzky:这不是专门化,不是模板的工作方式!它实际上也在做同样的事情。我也可以在那里插入模板,但这并不是一个很大的区别,是吗?只有在lambda没有捕获任何内容的情况下,这种到函数指针的转换才有效,对吗?对于上定义,这是正确的(调用程序是静态的)。但我相信这很容易解决。编辑:嗯,这确实可以很容易地解决-您将使用一个代理对象来捕获引用和对象,例如overgive\uu调用指向它的指针。我查看了N3559。如果没有捕获数据,静态函数和转换运算符仅在自动生成的lambda类中。
auto func(auto t) { ... }