在一个函数原型后面加上 "->" 是什么意思?

15
在这段代码中发生了什么?它非常混乱。
#include <utility>

struct check
{
   template <typename T>
   auto foo() -> decltype(std::declval<T>().value, void())
   {
      static_assert(T{}.value == 10, "Incorrect value");
   }
} var;

int main()
{
   struct apple
   {
      int value{10};
   };

   var.foo<apple>();
}

具体来说,需要翻译的是含有->及其后面所有内容的部分。


2
-> 是一个尾置返回类型。declval 创建一个类的实例。decltype 查找编译时表达式的类型。static_assert 是一个编译时断言。现在是将它们组合起来的时候了 :) - chris
3
标题模糊不利于其他有同样问题的人寻求帮助。 - Raymond Chen
1
@RiaD:虽然标题编辑更有帮助,但仍然不准确——他似乎在询问特定用途。 - Sion Sheevok
修改了标题,建议改为“函数原型后面的->是什么意思?” - Sion Sheevok
1个回答

10

让我们逐个解析。

auto foo() -> decltype(std::declval<T>().value, void())

这是一种尾返回类型。虽然允许使用参数,但在这里并不必要。我猜这样写是为了更清晰明了。`decltype` 找到内部表达式的类型,但该表达式实际上并未被评估。`std::declval` 用于创建传递给它的类型的实例。逗号运算符在此处用于使总体返回类型为 `void`,因为逗号运算符对左侧进行评估、丢弃它,然后对右侧进行评估并返回它。
第一部分创建了一种类似于 SFINAE 的东西(虽然我从未见过它被用在这种情况下)。例如,如果您有一个重载的 `foo`,它使用 `value2` 而不是 `value` 进行相同的操作,则不会存在调用哪个的歧义。参见此处的示例。将其与仅具有返回类型为 `void` 并引起错误的此处进行比较。
static_assert(T{}.value == 10, "Incorrect value");

这行代码确保一个值初始化的 T 实例,其 value 成员具有值 10。如果没有,则会生成一个带有该文本的编译器错误。
} var;

这只是一个全局对象,用于使用该类。
struct apple
{
   int value{10};
};

这是一个用于测试的示例类。它有一个value成员,对于值初始化的实例(默认初始化的实例也是如此),该成员的值为10。

var.foo<apple>();

这只是调用函数。


当我执行 struct grape {}; var.foo<grape>(); 时,它会给我一个错误。我该如何使其静默失败? - Me myself and I
@MemyselfandI,你需要有一个适用于像葡萄这样的结构体的 foo 版本。问题在于你必须确保使用 apple 调用它不会产生歧义。我会尝试准备一个例子。 - chris
@MemyselfandI,非常感谢Xeo,这里是链接。这个链接可以根据类型是否具有“value”数据成员来实现foo函数。 - chris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接