模板忽略[[nodiscard]]属性

时间:2018-11-20 11:14:32

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

当应用于函数时,[[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以便在此处发出警告?

2 个答案:

答案 0 :(得分:8)

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

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

答案 1 :(得分:2)

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

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

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