简体   繁体   English

C++20:非类型模板参数中的非捕获 lambda

[英]C++20: Non-capturing lambda in non-type template parameter

Does C++20 allow a non-capturing lambda decayed to a function pointer to be passed directly as a non-type template parameter? C++20 是否允许衰减为函数指针的非捕获 lambda 直接作为非类型模板参数传递? If so, what is the correct syntax?如果是这样,正确的语法是什么?

I have tried the following code in various versions of clang and gcc using -std=c++2a .我已经使用-std=c++2a在各种版本的 clang 和 gcc 中尝试了以下代码。

#include <iostream>

template<auto f>
struct S {
    static void invoke(int x) { f(x); }
};

using X = S<+[](int x) -> void { std::cout << x << " hello\n"; }>;

int main()
{
    X::invoke(42);
}

gcc compiles the code without complaint and the code runs as expected. gcc 毫无怨言地编译代码,代码按预期运行。

clang fails compilation with the following error: clang 编译失败并出现以下错误:

error: a lambda expression cannot appear in this context
using X = S<+[](int x) -> void { std::cout << x << " hello\n"; }>;
             ^

Here is the full code (online versions):这是完整的代码(在线版本):

Clang 10.0.0 HEAD: https://wandbox.org/permlink/n5eKQ4kQqSpDpr4k Clang 10.0.0 头: https : //wandbox.org/permlink/n5eKQ4kQqSpDpr4k

Gcc 10.0.0 HEAD 20200113: https://wandbox.org/permlink/vJ44sdMtwCKAFU64 Gcc 10.0.0 HEAD 20200113: https ://wandbox.org/permlink/vJ44sdMtwCKAFU64

Does C++20 allow a non-capturing lambda decayed to a function pointer to be passed directly as a non-type template parameter? C++20 是否允许衰减为函数指针的非捕获 lambda 直接作为非类型模板参数传递?

Yes.是的。

Indeed, you can go one step further - you don't even need to convert the lambda to a function pointer.事实上,您可以更进一步——您甚至不需要将 lambda 转换为函数指针。 You can just provide the lambda.您可以只提供 lambda。 This is valid C++20:这是有效的 C++20:

using Y = S<[](int x) -> void { std::cout << x << " hello\n"; }>;

The rule we have in C++20 is that lambdas are now allowed in unevaluated contexts ( P0315 ).我们在 C++20 中的规则是现在允许在未评估的上下文中使用 lambdas ( P0315 )。 Among many other wording changes there, this paper struck the rule that prevented lambdas from being used in template arguments ( C++17's [expr.prim.lambda]/2 ):在那里的许多其他措辞更改中,本文打破了阻止在模板参数中使用 lambda 的规则( C++17 的 [expr.prim.lambda]/2 ):

A lambda-expression shall not appear in an unevaluated operand, in a template-argument , in an alias-declaration , in a typedef declaration, or in the declaration of a function or function template outside its function body and default arguments. lambda 表达式不应出现在未计算的操作数、模板参数别名声明、typedef 声明中,或者出现在函数体和默认参数之外的函数或函数模板的声明中。

That clause does not exist anymore in C++20.该子句在 C++20 中不再存在。

Removing this restriction allows the lambda to be used as a template argument, and the conversion from captureless lambda to function pointer was already constexpr in C++17.取消这个限制允许将 lambda 用作模板参数,并且从无捕获 lambda 到函数指针的转换在 C++17 中已经是 constexpr。 clang simply does not implement this feature yet ( using T = decltype([]{}); compiles on gcc, not yet on clang). clang 还没有实现这个特性( using T = decltype([]{});在 gcc 上编译,还没有在 clang 上编译)。 I wouldn't call this a clang bug yet, it's just a clang not-yet-implemented-feature (lambdas in unevaluated contexts is not yet listed as implemented in the cppreference compiler support page ).我还不会称其为 clang 错误,它只是一个尚未实现的 clang 功能(未评估上下文中的 lambdas 尚未在cppreference 编译器支持页面中列出为已实现)。


C++20 non-type template parameters ( P1907 ) allows even dropping the + because captureless lambdas count as structural types ( [temp.param]/7 ) by way of simply not having any data members at all. C++20 非类型模板参数 ( P1907 ) 甚至允许删除+因为无捕获的 lambda 算作结构类型( [temp.param]/7 ),因为根本没有任何数据成员。

If the rules on this haven't changed since C++17 then using a lambda as a template parameter is not allowed for the same reason that using a string literal is not allowed.如果这方面的规则自 C++17 以来没有改变,则不允许使用 lambda 作为模板参数,原因与不允许使用字符串文字相同。 Every lambda has a different type and every string literal refers to a different object.每个 lambda 都有不同的类型,每个字符串字面量都指向不同的对象。 What changed in C++17 is that closure objects are now constexpr . C++17 中的变化是闭包对象现在是constexpr To use a string literal or a lambda as a template parameter, the object must have external linkage.要使用字符串文字或 lambda 作为模板参数,对象必须具有外部链接。 So this is allowed in C++17.所以这在 C++17 中是允许的。

template <auto>
struct S {};

constexpr const char string[] = "String literal";
constexpr auto lambda = []{};

S<string> a;
S<+lambda> b;

The closure object itself cannot be used as a template parameter (so you can't do S<lambda> ) but this might have changed in C++20 with three-way comparisons.闭包对象本身不能用作模板参数(因此您不能执行S<lambda> ),但这可能在 C++20 中通过三向比较发生了变化。 The reason the objects must have external linkage is because it kind of breaks templates.对象必须具有外部链接的原因是因为它破坏了模板。 S<+[]{}> and S<+[]{}> would be considered different types even though they look the same (similarly with S<""> ). S<+[]{}>S<+[]{}>将被视为不同的类型,即使它们看起来相同(与S<"">类似)。

Template parameter must be a constexpr variable.模板参数必须是constexpr变量。

There is a relevant proposal N4487 for lambdas.有一个针对 lambda 的相关提案N4487

I don't know if it made it into C++20.我不知道它是否使它成为 C++20。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用非类型模板参数的 C++20 概念对 class 模板进行完全特化 - Full specialisation of a class template using a C++20 concept of a non-type template parameter c++ 20中如何静态断言该类型对于模板非类型参数是可行的 - How to static_assert that type is viable for template non-type parameter in c++20 在 C++20 中是否允许通过非类型模板参数中的类类型传递函数指针? - Is passing of a function pointer through a class type in non-type template parameter allowed in C++20? 非类型模板参数的推导 class 类型的占位符是 C++20 功能吗? - Is placeholder for the deduced class type of non-type template parameter a C++20 feature? 结构非类型模板参数+聚合初始化:c++20标准与否 - Struct non-type template parameter + agregate initialization: standard in c++20 or not C++20 非类型模板参数,即先前类型参数中的模板:不是有效的模板参数,因为不是变量 - C++20 non-type template parameter which is template in the prior type parameters: is not a valid template arg, because is not a variable C++20 标准对使用子对象作为模板非类型 arguments 有什么看法? - What does the C++20 standard say about usage of subojects as template non-type arguments? 多态lambda的非类型模板参数? - Non-type template parameter for polymorphic lambda? 模板非类型参数? - Template non-type parameter? 非捕获 lambda 生命周期 - Non-capturing lambda lifecycle
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM