模板参数依赖 [[nodiscard]]
Template parameter dependant [[nodiscard]]
我有一个函数对象,它是另一个函数的包装器:
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();
}
如果 std::result_of<FuncT(ARG&&...)>::type
不是 void
,我想做的是将 operator()
标记为 [[nodiscard]]
。
我注意到,当我将 return 类型的模板评估的 [[nodiscard]]
放入 void
时,它只会被我的编译器忽略。
这是我可以依赖的行为吗,它是否以任何方式标准化?
[ 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 ]
我对这一段的阅读表明,给定
[[nodiscard]] void f() {}
甚至
f();
应该发出警告。您必须显式转换为 void
,如
(void) f();
压制它。所以不,标准不保证这一点。
在我看来,标准只是忽略了这个微妙之处。
您可以在两个重载 operator ()
之间使用 SFINAE 来 select:其中一个返回 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
}
我有一个函数对象,它是另一个函数的包装器:
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();
}
如果 std::result_of<FuncT(ARG&&...)>::type
不是 void
,我想做的是将 operator()
标记为 [[nodiscard]]
。
我注意到,当我将 return 类型的模板评估的 [[nodiscard]]
放入 void
时,它只会被我的编译器忽略。
这是我可以依赖的行为吗,它是否以任何方式标准化?
[ 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 markednodiscard
. Appearance of a nodiscard call as a potentially-evaluated discarded-value expression is discouraged unless explicitly cast tovoid
. 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 ]
我对这一段的阅读表明,给定
[[nodiscard]] void f() {}
甚至
f();
应该发出警告。您必须显式转换为 void
,如
(void) f();
压制它。所以不,标准不保证这一点。
在我看来,标准只是忽略了这个微妙之处。
您可以在两个重载 operator ()
之间使用 SFINAE 来 select:其中一个返回 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
}