关于函数模板中定义的lambda闭包的类型可以怎么说?

Pic*_*ent 3 c++ lambda language-lawyer

我知道lambda的类型是“隐藏的”并且是唯一的。但是“唯一”的确切含义是什么,在相同的lambda代码中,奇异的代码具有相同的类型吗?

(如果可能的话)我想使用此“不变式”进行类型检查,如下所示:

#include <type_traits>

template <typename T>
auto foo(const T y)
{
  return [=](T x) { return x * y; }; 
}

int main()
{
  auto f1 = foo<int>(4.);
  auto f2 = foo<int>(6.); // fails with auto f2 = foo<double>(6.);

  static_assert(std::is_same_v<decltype(f1), 
                               decltype(f2)>); // is this ok or undefined behavior?
}
Run Code Online (Sandbox Code Playgroud)

在此之前,我想确定C ++标准所说的是什么?是正常的还是不确定的行为?

(此代码已通过g ++和clang ++成功编译,但只有标准真相才重要)


由于补语更符合初始标题(抱歉,由于我不得不离开办公室,所以来得有点晚),这是一个无法编译的更强版本:

#include <type_traits>

template <typename T>
auto foo_1(const T y)
{
  return [=](T x) { return x * y; };
}

template <typename T>
auto foo_2(const T y)
{
  return [=](T x) { return x * y; };
}

int main()
{
  auto f1 = foo_1<int>(4.);
  auto f2 = foo_2<int>(6.);

  static_assert(std::is_same_v<decltype(f1), decltype(f2)>); // fails!
}
Run Code Online (Sandbox Code Playgroud)

Bri*_*ian 6

确实,该标准并未确切说明“独特”的含义,但我认为我们可以弄清楚。

首先,请注意该标准说“唯一的,未命名的非工会类类型”。形容词“未命名”的强度足以暗示lambda闭包类型与使用structor class关键字或标准库定义的某些命名类从不相同(例如,lambda闭包类型不能为std::function<...>)。

那么,为什么标准说“唯一,未命名”?它一定在告诉我们一些关于两种不同的lambda闭包类型之间的比较的信息。尽管如此,在许多情况下这还是多余的。如果我们有两个lambda表达式,例如:

auto f1 = [](int x) { return x; };
auto f2 = [](int x) { return 2*x; };
Run Code Online (Sandbox Code Playgroud)

显然,两个lambda表达式不能具有相同的类型,因为它们的函数调用运算符具有不同的行为。因此,每个闭包类型都是“唯一”的声明不会告诉我们任何我们还不了解f1和的信息f2

但是,如果我们现在来看:

auto f3 = [](int x) { return x; };
auto f4 = [](int x) { return x; };
Run Code Online (Sandbox Code Playgroud)

在这里,“独一无二”,可以理解为说f3f4肯定有不同的类型,即使lambda表达式有相同的拼写和相同的行为。

在这种情况下,这通常被接受为“唯一”的含义。如果该标准不是要这么说f3并且f4具有不同的类型,那么根本就没有理由使用“独特”一词。相反,它只会说“未命名”,而不是“唯一,未命名”。

然后就产生了关于唯一性延伸到多远的问题。可能意味着lambda表达式的每次评估产生不同的类型吗?不,这不可能意味着那个。这将使表达式的静态类型取决于它被执行了多少次(运行时属性),这是荒谬的。考虑一下,如果您foo<int>的lambda每次foo<int>执行时都有不同的类型,将会发生什么情况。这意味着foo<int>的签名每次被调用时都会改变。这不可能。输入中的lambda foo<int>必须始终具有相同的类型。

至于您foo_1和的foo_2情况,两种lambda类型必须不同。同样,如果不是这样,“独特”一词将是多余的。