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?
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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With