c++attributesc++17nodiscard

Template parameter dependant [[nodiscard]]


I have a functional object which is a wrapper around another function:

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();
}

What I would like to do is to mark the operator() as [[nodiscard]] if the std::result_of<FuncT(ARG&&...)>::type is not void.

What I have noticed is that when I do put the [[nodiscard]] in case of the template evaluation of return type to void, it will simply get ignored by my compiler.

Is this the behaviour I can rely on, is it in any way standarized?


Solution

  • Per [dcl.attr.nodiscard]/2:

    [ Note: A nodiscard call is a function call expression that calls a function previously declared nodiscard, or whose return type is a possibly cv-qualified class or enumeration type marked nodiscard. Appearance of a nodiscard call as a potentially-evaluated discarded-value expression is discouraged unless explicitly cast to void. Implementations should issue a warning in such cases. This is typically because discarding the return value of a nodiscard call has surprising consequences. — end note ]

    My reading of this paragraph gives that, given

    [[nodiscard]] void f() {}
    

    even

    f();
    

    should issue a warning. You have to explicitly cast to void as in

    (void) f();
    

    to suppress it. So no, this is not guaranteed by the standard.

    It seems to me that the standard simply overlooked this subtlety.