我有一个功能对象,它是另一个功能的包装:
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
的情况下,它将被编译器忽略。
这是我可以依靠的行为吗,在任何方面都可以证明吗?
答案 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)
[注意:” nodiscard调用是一个函数调用表达式,它调用一个 先前声明为
nodiscard
或返回类型为 可能标记为nodiscard
的具有cv资格的类或枚举类型。 Nodiscard呼叫显示为可能评估的对象 除非明确将其强制转换为void
。在这种情况下,实现应发出警告。这是 通常是因为丢弃nodiscard调用的返回值有 令人惊讶的后果。 — 尾注]
我对本段的阅读给出了这一点
[[nodiscard]] void f() {}
偶
f();
应发出警告。您必须像在
中那样明确地转换为void
(void) f();
抑制它。所以不,这不是标准所保证的。
在我看来,该标准只是忽略了这种微妙之处。