我正在尝试确定是否可以以不能忽略返回值的方式声明C ++函数(理想情况下在编译时检测到)。我尝试使用private
(或在C ++ 11,delete
d)operator void()
中声明一个类,以便在未使用返回值时尝试捕获隐式转换为void。 / p>
这是一个示例程序:
class Unignorable {
operator void();
};
Unignorable foo()
{
return Unignorable();
}
int main()
{
foo();
return 0;
}
不幸的是,我的编译器(clang-703.0.31)说:
test.cpp:2:5: warning: conversion function converting 'Unignorable' to 'void' will never be used
operator void();
^
并且不会在致电foo()
时出现任何错误或警告。所以,那是行不通的。有没有其他方法可以做到这一点?特定于C ++ 11或C ++ 14或更高版本的答案可以。
答案 0 :(得分:8)
总结其他答案&评论,基本上你有3个选择:
[[nodiscard]]
__wur
这样的编译器扩展(已定义
作为__attribute__ ((__warn_unused_result__))
),或更可移植(仅限C ++ 11及以上)[[gnu::warn_unused_result]]
属性。如果所有这3个都不可能,那么还有一种方法,即"负面编译" 。定义您的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
};
现在使用-DNEGATIVE_COMPILE
或其他编译器(如MSVC)进行编译。它会在未被忽略:
auto x = foo(); // error
但是,无论何处被忽略,它都不会给出任何错误:
foo(); // no error
使用任何现代代码浏览器(如eclipse-cdt),您可能会发现foo()
的所有出现并修复那些没有出错的地方。在新编辑中,只需删除" NEGATIVE_COMPILE"的预定义宏。
与简单地查找foo()
并检查其返回值相比,这可能会更好一些,因为可能有许多函数,例如foo()
,您可能不想忽略返回值。
这有点单调乏味,但适用于所有编译器的所有C ++版本。
答案 1 :(得分:6)
见__attribute__ ((warn_unused_result))。
Failed to start service jboss.persistenceunit."app.ear#PU": org.jboss.msc.service.StartException in service jboss.persistenceunit."PU": javax.persistence.PersistenceException: [PersistenceUnit: PU] Unable to build Hibernate SessionFactory
...
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: PU] Unable to build Hibernate SessionFactory
...
Caused by: org.hibernate.tool.schema.spi.SchemaManagementException: Unable to execute schema management to JDBC target [create index company_id_index on APPROVER (COMPANY_ID)]
...
Caused by: org.postgresql.util.PSQLException: ERROR: relation "company_id_index" already exists
然后强制警告为错误:
int foo() __attribute__ ((warn_unused_result));
int foo(){return 123;}
int main()
{
foo(); //compiler warning
auto i = foo(); //valid
}
答案 2 :(得分:5)
在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();
}
概要:一个函数返回一个angry<T>
而不是返回一个T,如果在销毁之前没有提取该值,则抛出logic_error
来惩罚调用者。
这是一个运行时解决方案,这是一个限制,但至少应该在单元测试中尽早发现。
精明的用户当然可以颠覆它:
foo().get(); // won't throw
答案 3 :(得分:1)
如果使用MFC,则可以在函数声明之前尝试 Check_return 。 在Annotating function behavior
上了解更多