Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 357
cerkiewny Avatar asked Jun 12 '19 08:06

cerkiewny


1 Answers

You can use SFINAE to select between two overloaded operator (): one of them returning void, and another one for the rest of cases annotated with the [[nodiscard]] attribute:

#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
}
like image 148
metalfox Avatar answered Oct 19 '22 18:10

metalfox