Gre*_*ill 24 c++ return-value void
我正在尝试确定是否可以以不能忽略返回值的方式声明C++函数(理想情况下,在编译时检测到).我尝试使用private
(或在C++ 11,delete
d中)声明一个类,operator void()
以便在未使用返回值时尝试捕获隐式转换为void.
这是一个示例程序:
class Unignorable {
operator void();
};
Unignorable foo()
{
return Unignorable();
}
int main()
{
foo();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,我的编译器(clang-703.0.31)说:
test.cpp:2:5: warning: conversion function converting 'Unignorable' to 'void' will never be used
operator void();
^
Run Code Online (Sandbox Code Playgroud)
并且不会在通话时发出任何错误或警告foo()
.所以,那是行不通的.有没有其他方法可以做到这一点?特定于C++ 11或C++ 14或更高版本的答案可以.
总结其他答案和评论,基本上你有3个选择:
[[nodiscard]]
__wur
(如(定义为__attribute__ ((__warn_unused_result__))
))或更可移植(仅限C++ 11及更高版本)[[gnu::warn_unused_result]]
属性.如果所有这三个都不可能,那么还有一种方法,就是"负面编译".定义Unignorable
如下:
struct Unignorable {
Unignorable () = default;
#ifdef NEGATIVE_COMPILE
Unignorable (const Unignorable&) = delete; // C++11
Unignorable& operator= (const Unignorable&) = delete;
//private: Unignorable (const Unignorable&); public: // C++03
//private: Unignorable& operator= (const Unignorable&); public: // C++03
/* similar thing for move-constructor if needed */
#endif
};
Run Code Online (Sandbox Code Playgroud)
现在-DNEGATIVE_COMPILE
在MSVC等其他编译器中编译或等效.它会在结果不被忽略的地方给出错误:
auto x = foo(); // error
Run Code Online (Sandbox Code Playgroud)
但是,无论何处忽略结果,它都不会给出任何错误:
foo(); // no error
Run Code Online (Sandbox Code Playgroud)
使用任何现代代码浏览器(如eclipse-cdt),您可以找到所有出现foo()
并修复那些没有给出错误的地方.在新编译中,只需删除"NEGATIVE_COMPILE"的预定义宏.
与简单地查找foo()
和检查其返回值相比,这可能会更好一些,因为可能有许多函数,例如foo()
您可能不想忽略返回值.
这有点单调乏味,但适用于所有编译器的所有C++版本.
请参阅__attribute __((warn_unused_result)).
int foo() __attribute__ ((warn_unused_result));
int foo(){return 123;}
int main()
{
foo(); //compiler warning
auto i = foo(); //valid
}
Run Code Online (Sandbox Code Playgroud)
然后强制警告是一个错误:
clang++ -std=c++1z -Werror="unused-result"
Run Code Online (Sandbox Code Playgroud)
在c ++ 17之前,我想到了这种方法:
#include <stdexcept>
#include <exception>
#include <boost/optional.hpp>
// proxy object which complains if it still owns the return
// value when destroyed
template<class T>
struct angry
{
angry(T t) : value_(std::move(t)) {}
angry(angry&&) = default;
angry(angry const&) = default;
angry& operator=(angry&&) = default;
angry& operator=(angry const&) = default;
~angry() noexcept(false)
{
if (value_) throw std::logic_error("not used");
}
T get() && {
T result = std::move(value_).value();
value_.reset();
return result;
}
boost::optional<T> value_;
};
// a function which generates an angry int
angry<int> foo()
{
return 10;
}
int main()
{
// obtain an int
auto a = foo().get();
// this will throw
foo();
}
Run Code Online (Sandbox Code Playgroud)
概要:一个函数返回一个函数,而不是返回一个T,如果在销毁之前未提取该值,则angry<T>
抛出一个将惩罚调用者logic_error
.
这是一个运行时解决方案,这是一个限制,但至少应该在单元测试中尽早发现.
一个精明的用户当然可以颠覆它:
foo().get(); // won't throw
Run Code Online (Sandbox Code Playgroud)