取决于模板参数的[[nodiscard]]

时间:2019-06-12 08:30:06

标签: c++ attributes c++17

我有一个功能对象,它是另一个功能的包装:

template <typename FuncT>
class Wrapper
{
    private:
        FuncT funcToWrap;

    public:
        Wrapper(FuncT ftw) : funcToWrap(ftw){};

        template<typename ...ARG>
        typename std::result_of<FuncT(ARG&&...)>::type operator()(ARG&&... args){
            return funcToWrap(std::forward<ARG>(args)...);
        }
};

int main(){
    std::function<void()> testfunc = [](){ std::cout << "Test" << std::endl; };
    Wrapper<decltype(testfunc)> test{testfunc};
    test();
}

如果operator()不是[[nodiscard]],我想做的就是将std::result_of<FuncT(ARG&&...)>::type标记为void

我注意到的是,如果我将[[nodiscard]]放在返回类型的模板评估为void的情况下,它将被编译器忽略。

这是我可以依靠的行为吗,在任何方面都可以证明吗?

2 个答案:

答案 0 :(得分:2)

您可以使用SFINAE在两个重载的operator ()之间进行选择:其中一个返回void,对于其余的情况,其中一个返回[[nodiscard]]属性:

#include <type_traits>
#include <iostream>

template <typename FuncT>
class Wrapper
{
    private:
        FuncT funcToWrap;

    public:
        Wrapper(FuncT ftw) : funcToWrap(ftw) {}

        template <typename ...ARG, typename T = std::invoke_result_t<FuncT, ARG...>>
        std::enable_if_t<std::is_void_v<T>> operator()(ARG&&... args) {
            std::cout << "Test 1" << std::endl;
            return funcToWrap(std::forward<ARG>(args)...);
        }

        template <typename ...ARG, typename T = std::invoke_result_t<FuncT, ARG...>>
        [[nodiscard]] std::enable_if_t<!std::is_void_v<T>, T> operator()(ARG&&... args) {
            std::cout << "Test 2" << std::endl;
            return funcToWrap(std::forward<ARG>(args)...);
        }
};

int main() {
    auto testfunc1 = [] { };
    Wrapper test1{testfunc1};
    test1(); // <-- No warnings should be issued here

    auto testfunc2 = [] { return 0; };
    Wrapper test2{testfunc2};
    test2(); // <-- Warning issued here
}

答案 1 :(得分:0)

[dcl.attr.nodiscard]/2

  

[注意:” nodiscard调用是一个函数调用表达式,它调用一个   先前声明为nodiscard或返回类型为   可能标记为nodiscard的具有cv资格的类或枚举类型。   Nodiscard呼叫显示为可能评估的对象   除非明确将其强制转换为   void。在这种情况下,实现应发出警告。这是   通常是因为丢弃nodiscard调用的返回值有   令人惊讶的后果。 — 尾注]

我对本段的阅读给出了这一点

[[nodiscard]] void f() {}

f();

应发出警告。您必须像在

中那样明确地转换为void
(void) f();

抑制它。所以不,这不是标准所保证的。

在我看来,该标准只是忽略了这种微妙之处。