我可以将 C++17 无捕获 lambda constexpr 转换运算符的结果用作函数指针模板非类型参数吗?

Posted

技术标签:

【中文标题】我可以将 C++17 无捕获 lambda constexpr 转换运算符的结果用作函数指针模板非类型参数吗?【英文标题】:Can I use the result of a C++17 captureless lambda constexpr conversion operator as a function pointer template non-type argument? 【发布时间】:2018-05-16 08:25:39 【问题描述】:

在回答 How do I write a lambda expression that looks like a method? 时,我尝试利用以下事实将无捕获 lambda 转换为成员函数指针:自 C++17 以来,无捕获 lambda 对其函数有一个 constexpr 转换运算符指针类型。

所以我想出了一个归结为:

template<void(*)()> struct A;

int main()

  A<static_cast<void(*)()>([])>; // 1

  constexpr auto fp = static_cast<void(*)()>([]);
  A<fp>; // 2

现在,它在 clang 中编译(从 5.0.0 开始)但 gcc(>=7.2) 抱怨:

error: lambda-expression in template-argument
   A<static_cast<void(*)()>([] /*whatever*/ )>; // 1
                            ^
error: 'main()::<lambda()>::_FUN' is not a valid template argument for type 'void (*)()' because 'static constexpr void main()::<lambda()>::_FUN()' has no linkage
   A<fp>; // 2

问题是,谁是对的?

【问题讨论】:

应该有一个使用 constexpr 局部变量的更简单的例子,不是吗? @Yakk,完成;这并不完全等同于原始代码......还是不? 我不禁想知道您到底想做什么以及为什么需要这样做。 指向没有链接的函数的指针应该被允许在 C++17 中作为非类型模板参数。见N4198。 @massim 不太一样,但简单了 3 倍。我可以看到用途;尽可能快地委托便携式版本。 【参考方案1】:

这是一个 gcc 错误,已提交 83258。

在 C++14 中,我们曾经有一个 linkage requirement 用于指针类型的非类型模板参数。但是在 C++17 中(作为N4268 的结果),参数只需要是正确类型的converted constant expression,还有一些其他限制(这里都不相关)。一旦我们可以构造fp,我们应该能够将它用作模板参数。

【讨论】:

以上是关于我可以将 C++17 无捕获 lambda constexpr 转换运算符的结果用作函数指针模板非类型参数吗?的主要内容,如果未能解决你的问题,请参考以下文章

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

捕获列表中的 C++ lambda 复制值

在 C++11 中按值或引用使用 lambda 默认捕获的缺点?

c# 在 Lambda 表达式中声明变量

可以在 C++11 lambda 中隐式捕获参数包吗?

c ++ lambdas如何从上层范围捕获可变参数包