【问题标题】:Why isn't a lambda allowed in a template instantiation?为什么模板实例化中不允许使用 lambda?
【发布时间】:2019-05-04 09:00:08
【问题描述】:

我目前正在处理一些需要使用 lambda 作为模板参数的代码,如下例所示:

#include <iostream>

template<void(*func)(int)>
struct FunctionCaller{
    FunctionCaller() {func(5);}
};

void RealFunction(int i){
    std::cout << i*2 << std::endl;
}

int main(){
    FunctionCaller<[](int i){std::cout << i << std::endl;}> caller; //should print 5
    FunctionCaller<RealFunction> caller2; //should print 10
    return 0;
}

我尝试使用 GCC 和 Clang 的最新(支持 C++17)版本(分别为 8.2.1 和 7.0.0 版本)编译此示例,以获取各种错误,这些错误相当于模板参数中不允许使用 lambda 表达式。我正在使用正确的编译器标志来启用 C++17 支持。

然而,这在我看来应该可以工作,因为《C++ Primer 5th edition》一书说任何常量表达式都可以用于非类型模板参数,并且在 C++17 中,这个 Stack Overflow 帖子告诉我lambda 是 C++17 及更高版本中的常量表达式。

经过广泛研究,似乎 C++17 标准明确禁止将 lambdas 作为模板参数。这种限制背后的理由是什么?如果不到位会爆炸什么?

编辑:This 问题有一些相关信息,但它只是说存在此限制是为了防止 lambda 出现在方法签名中,而没有任何信息说明为什么会出现问题。

【问题讨论】:

  • 这个问题不是链接问题的重复,因为该问题与 STL 模板的使用有关,而这个问题是关于创建新的类模板。此外,链接问题的已接受答案说模板不能在类似 decltype 的上下文中使用(未评估),但可以肯定的是,实例化调用 lambda 的模板会评估该 lambda。
  • 你也可以看看stackoverflow.com/questions/1174169/… 可以解决你的问题
  • @VasanthAlagiriswamy 我知道一些解决方法,但我不知道为什么我的原始解决方案不起作用这一事实表明我的 C++ 知识存在一个漏洞,我想纠正。跨度>
  • @PasserBy 唯一相关的信息是这确实是故意的,并且由于某种原因,方法签名中的 lambdas 是一个问题。目前尚不清楚为什么这是个问题。

标签: c++ templates lambda language-lawyer c++17


【解决方案1】:

经过一番搜索,我发现了引入此限制的更改:core issue 1607。它说:

关于函数模板签名中的 lambda-expressions 的进一步讨论出现了。尽管 lambda-expressions 不能作为未计算的操作数出现的限制(8.1.5 [expr.prim.lambda] 第 2 段)旨在避免在函数模板签名中处理它们的需要,但事实上8.20 [expr.const] 将未计算的子表达式与未计算的操作数分开处理,为模板签名中的 lambda-expressions 开辟了另一条途径,例如,

template<typename T>
void f(int [(0 && [] { for (auto x : T()) {} }, 1)]);

Core 提供了 EWG 4 选项,他们选择了我们在 C++17 及之前的选项:在签名中禁止 lambda - 所以模板参数等。

现在为什么 lambda 不应该出现在函数模板签名中?这在N2903 中有解释:

此外,此重写增加了 lambda 表达式不能用于 sizeof 运算符、alignof 运算符或 decltype 说明符的操作数的限制。这种限制——由 Doug Gregor 和 John Spicer 提出——避免了模板参数推导的严重实现困难(例如,这避免了在错误名称中编码任意语句序列的需要)。

【讨论】:

    猜你喜欢
    • 2022-06-26
    • 1970-01-01
    • 2013-09-05
    • 1970-01-01
    • 1970-01-01
    • 2013-05-05
    • 2019-05-20
    • 1970-01-01
    • 2011-02-02
    相关资源
    最近更新 更多