【问题标题】:Template ignores [[nodiscard]] attribute模板忽略 [[nodiscard]] 属性
【发布时间】:2018-11-20 11:14:31
【问题描述】:

当应用于函数时,[[nodiscard]] 属性鼓励编译器在被丢弃的表达式中使用而不是强制转换为void 时发出警告。示例:

[[nodiscard]] int callable_return_not_discardable(int n)
{ return n; }

int main()
{
    callable_return_not_discardable(0); // warning/error:
        // ignoring return value of 'int callable_return_not_discardable(int)',
        // declared with attribute nodiscard [-Wunused-result]
    (void) callable_return_not_discardable(0); // OK
}

gcc-8clang-7 上进行现场演示。


这很好而且有用,直到添加了一个额外的间接层:模板:

template<class Callable>
void invoke_with_answer(Callable&& callable)
{ callable(42); }

[[nodiscard]] int callable_return_not_discardable(int n)
{ return n; }

int main()
{
    invoke_with_answer(callable_return_not_discardable); // OK
}

gcc-8clang-7 上的现场演示。

那么我的问题是:
这是一个缺失的功能,是什么模板的结果,还是应该修复 clang 和 gcc 以在此处发出警告?

【问题讨论】:

  • 这与模板无关。如果您将第一行替换为using Callable = int(int);,您将获得完全相同的行为。 行为是函数指针是什么的结果(参见 StoryTellers 的回答)。
  • @Handy 你好。在评论部分回复通常是不受欢迎的。如果您认为可以改进答案,请提出修改建议或自行回答。

标签: c++ gcc clang language-lawyer c++17


【解决方案1】:

[[nodiscard]] 不是函数签名或类型的一部分,并且在将所述函数转换为指针或绑定到引用时根本不会保留。这正是您的示例所做的。

出于所有意图和目的,模板无法“看到”该属性。

【讨论】:

  • @你打败了我,所以我不妨挑剔我正在验证的东西:)
  • 嗯,标准中有“属于函数类型的属性”之类的东西。这不是说属性信息没有丢失吗?
  • @Rakete1111 - 一个属性必须适用于函数的类型才能保持。而[[nodiscard]] 根本不是。这可能只是一个疏忽。
【解决方案2】:

由于explained by StorryTeller[[nodiscard]] 不是函数签名或类型的一部分,这就是该信息在模板主体的上下文中丢失的原因。

传播该警告的解决方案是将[[nodiscard]] 属性添加到该函数的返回type

template<class Callable>
void invoke_with_answer(Callable&& callable)
{ callable(42); } // warning

struct [[nodiscard]] Int { int value; };

Int callable_return_not_discardable(int n)
{ return {n}; }

int main()
{
    invoke_with_answer(callable_return_not_discardable); // note
}

Live demo on gcc-8

【讨论】:

  • enum [[nodiscard]] Int : int{}; 也是整数类型的一个选项。至少您可以毫不费力地转换为int
  • @StoryTeller 这是真的 :) 我会照原样做,因为这不是重点,而是真的 ^^。
  • @StoryTeller-UnslanderMonica 是吗?我不太明白,枚举是空的,所以任何自省工具/库都会/应该将所有整数报告为不属于枚举值的一部分。这不会造成更多问题吗?
  • @LorahAttkins - 底层类型的所有整数都是枚举的一部分。枚举器只是范围内的命名常量(它们可以完全省略)。这不是什么深奥的东西,因为这正是 std::byte 的定义方式(尽管是范围枚举)。自省工具针对某些用例采用启发式方法,但并非没有错误警告。
猜你喜欢
  • 2021-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-23
  • 2012-03-13
  • 2019-10-26
  • 1970-01-01
相关资源
最近更新 更多