当前位置: 首页 > 知识库问答 >
问题:

lambda表达式是合法的默认(非类型模板)参数吗?

轩辕华辉
2023-03-14

以下所有标准参考文件均参考N4861(2020年3月布拉格后工作草案/C 20 DIS)

在Q中

template<auto v>
constexpr auto identity_v = v;

constexpr auto l1 = [](){};
constexpr auto l2 = identity_v<l1>;

现在,根据[expr.prim.lambda.closure]/1,每个lambda表达式的类型都是唯一的

[...] 一个唯一的、未命名的非并集类类型,称为闭包类型[…]

另一方面,[basic.def.odr]/1[extract,emphasis-mine]表示

任何翻译单元不得包含一个以上的任何变量、函数、类类型、枚举类型、模板、参数的默认参数(对于给定范围中的函数)或默认模板参数的定义。

可以说,这意味着默认模板参数被视为需要尊重ODR的定义。

... 这就引出了我的问题:

  • lambda表达式是合法的默认(非类型模板)参数吗?如果是,这是否意味着使用这种默认参数的每个实例化都会实例化一个唯一的专门化

(如果接近非法,也请突出显示:例如,超出单个实例化的任何内容是否会导致ODR违规)。

如果这实际上是合法的,那么每次调用一个带有lambda作为默认参数的变量模板都会导致一个唯一专业化的实例化:

template<auto l = [](){}>
               // ^^^^^^ - lambda-expression as default argument
constexpr auto default_lambda = l;

static_assert(!std::is_same_v<
    decltype(default_lambda<>),
    decltype(default_lambda<>)>);

GCC(演示)和Clang(演示)都接受上述程序

如果编译器正确地接受了这个例子,这意味着允许另一种机制捕获和检索元编程状态,这种技术长期以来被认为是

...神秘,应该变得不成形。

共有1个答案

颜黎昕
2023-03-14

lambda表达式是合法的默认(非类型模板)参数吗?如果是,这难道不意味着使用这种默认参数的每个实例化都实例化了一个唯一的专门化吗?

是的,这意味着给定模板变量:

template<auto l = [](){}>
constexpr auto default_lambda = l;

default\u lambda的每次调用都将通过生成新的唯一闭包类型生成一个新的模板实例化,从而提供一种捕获元编程状态的新方法。

因此,必须重新计算使用default\u lambda的每个表达式。如果编译器的状态自上次实例化以来发生了更改,并且如果我们在依赖表达式中使用它(例如:检查是否定义了类型),那么表达式的结果可能会更改。例如:

struct X; // not defined

template <typename T, auto = default_lambda<>>
consteval bool is_defined() {
    if constexpr (requires { T{}; }) {
        return true;
    } else {
        return false;
    }
}

static_assert(is_defined<X>() == false);

struct X {};
static_assert(is_defined<X>() == true);
 类似资料:
  • 如果允许我执行以下操作: 为什么我主要不被允许做以下事情? 但我必须具体说明以下几点: C11引入了默认的模板参数,现在我完全无法理解它们。

  • OpenGL定义了C函数来管理资源。我编写了一个简单的包装器来以RAII的方式处理它们。函数对类似于和。但是,也有一些函数对适用于资源数组,例如和。对于前者,我编写了一个简单的类来完成这项工作,对于后者,我编写了另一个处理数组的类。然而,我注意到有时我只使用一个缓冲区或纹理,在那里我不必承担向量的费用,我想如果发布函数在开始时采用大小参数,我会专门化类析构函数,但是... 对于上述SSCCE g树

  • 问题内容: 当我运行它时,它拒绝“ def a(…”,并用红色突出显示“(”。我不知道为什么。 问题答案: 让我在这里澄清两点: 首先,非默认参数不应跟随默认参数,这意味着您无法在函数中定义。在函数中定义参数的正确顺序为: 位置参数或非默认参数,即 关键字参数或默认参数,即 仅关键字参数,即 var-keyword参数,即 是位置参数 是可选参数 是关键字参数 是列表参数 仅限关键字 是var-k

  • 是否允许在友元声明中为模板参数提供默认值? Visual Studio 2015似乎允许这样做。gcc拒绝了。我在cppreference页面上找不到任何内容。

  • 我试图理解下面的代码片段 当使用指针类型示例int*调用时,默认参数是如何工作的? 当obj1.test()被调用时,编译器将生成什么。我得到一个编译器错误当我尝试

  • 问题内容: 我试图通过使用Runnable接口包装我需要的任何函数来简单地计时一个函数。 那么我可以简单地执行以下操作: 但是,如果我有一个带有参数的函数,则必须将其修改为: 我遇到的问题是’someParameter’必须是final或有效的final。有没有解决此问题的方法?我见过forEach的循环,但是我需要将此参数从1、10、100->指数化直到满足条件。代码是这样的: 我要求funct