在 c++03 及更早版本中,为了禁用关于未使用参数的编译器警告,我通常使用这样的代码:
#define UNUSED(expr) do { (void)(expr); } while (0)
例如
int main(int argc, char *argv[])
{
UNUSED(argc);
UNUSED(argv);
return 0;
}
但是宏不是 C++ 的最佳实践,所以。 c++11标准有没有更好的解决方案?我的意思是我可以摆脱宏吗?
谢谢大家!
(void)argc;
比 UNUSED(argc);
更短更清晰
unused(argc, argv)
和 template<class... T> void unused(T&&...){}
。清晰,简洁,没有宏。
void foo(int /*unused_arg*/, int used_arg)
您可以省略参数名称:
int main(int, char *[])
{
return 0;
}
在 main 的情况下,您甚至可以完全省略参数:
int main()
{
// no return implies return 0;
}
请参阅 C++11 标准中的“§ 3.6 开始和终止”。
C++11 中有 <tuple>
,其中包括准备使用的 std::ignore
对象,它允许我们编写(很可能不会产生运行时开销):
void f(int x)
{
std::ignore = x;
}
为此,我使用了一个带有空主体的函数:
template <typename T>
void ignore(T &&)
{ }
void f(int a, int b)
{
ignore(a);
ignore(b);
return;
}
我希望任何认真的编译器都能优化函数调用,并为我消除警告。
T
是模板参数时,T&&
是绑定到任何东西的通用引用。
要“禁用”这个警告,最好避免写参数,只写类型。
void function( int, int )
{
}
或者,如果您愿意,请将其注释掉:
void function( int /*a*/, int /*b*/ )
{
}
您可以混合命名和未命名的参数:
void function( int a, int /*b*/ )
{
}
使用 C++17 你有 [[maybe_unused]] 属性说明符,比如:
void function( [[maybe_unused]] int a, [[maybe_unused]] int b )
{
}
/* ... */
注释掉大块代码
#if 0
块灰显作为一种特殊情况,即使它们不支持完整的预处理器智能感知。
没有什么等价的,不。
所以你坚持使用相同的旧选项。您愿意完全省略参数列表中的名称吗?
int main(int, char**)
当然,在 main
的特定情况下,您可以简单地省略参数本身:
int main()
还有一些典型的特定于实现的技巧,例如 GCC 的 __attribute__((unused))
。
你有什么反对旧的和标准的方式?
void f(int a, int b)
{
(void)a;
(void)b;
return;
}
宏可能并不理想,但它们在这个特定目的上做得很好。我会说坚持使用宏。
MAYBE_UNUSED
;我通常不在乎我是否说过“如果我在下面不使用它,请不要担心”,但无论如何都要继续这样做。
Boost 标头 <boost/core/ignore_unused.hpp>
(Boost >= 1.56) 为此目的定义了函数模板 boost::ignore_unused()
。
int fun(int foo, int bar)
{
boost::ignore_unused(bar);
#ifdef ENABLE_DEBUG_OUTPUT
if (foo < bar)
std::cerr << "warning! foo < bar";
#endif
return foo + 2;
}
PS C++17 具有 [[maybe_unused]]
属性来抑制未使用实体的警告。
[[maybe_unused]]
是显式方式,目前最好。
没有什么新东西可用。
最适合我的是在实现中注释掉参数名称。这样,您就可以摆脱警告,但仍然保留有关参数是什么的一些概念(因为名称可用)。
您的宏(以及所有其他强制转换为 void 的方法)的缺点是您可以在使用宏后实际使用该参数。这会使代码更难维护。
我真的很喜欢为此使用宏,因为它可以让您更好地控制何时有不同的调试版本(例如,如果您想在启用断言的情况下进行构建):
#if defined(ENABLE_ASSERTS)
#define MY_ASSERT(x) assert(x)
#else
#define MY_ASSERT(x)
#end
#define MY_UNUSED(x)
#if defined(ENABLE_ASSERTS)
#define MY_USED_FOR_ASSERTS(x) x
#else
#define MY_USED_FOR_ASSERTS(x) MY_UNUSED(x)
#end
然后像这样使用它:
int myFunc(int myInt, float MY_USED_FOR_ASSERTS(myFloat), char MY_UNUSED(myChar))
{
MY_ASSERT(myChar < 12.0f);
return myInt;
}
对于时间关键的代码段,我有自己的实现。我一直在研究用于减速的时间关键代码,发现这个实现消耗了我正在优化的时间关键代码的 2%:
#define UTILITY_UNUSED(exp) (void)(exp)
#define UTILITY_UNUSED2(e0, e1) UTILITY_UNUSED(e0); UTILITY_UNUSED(e1)
#define ASSERT_EQ(v1, v2) { UTILITY_UNUSED2(v1, v2); } (void)0
时间关键代码已将 ASSERT*
定义用于调试目的,但在发布时它显然已被删除,但是......似乎这个在 Visual Studio 2015 Update 3
中产生了更快的代码:
#define UTILITY_UNUSED(exp) (void)(false ? (false ? ((void)(exp)) : (void)0) : (void)0)
#define UTILITY_UNUSED2(e0, e1) (void)(false ? (false ? ((void)(e0), (void)(e1)) : (void)0) : (void)0)
原因在于双 false ?
表达式。它以某种方式在发布时产生了更快的代码,并具有最大的优化。
我不知道为什么这更快(似乎是编译器优化中的一个错误),但对于这种代码情况,它至少是一个更好的解决方案。
注意:这里最重要的是,时间关键型代码会在没有上述断言或发布中未使用的宏的情况下减慢速度。换句话说,双 false ?
表达式惊人地有助于优化代码。
windows.h 定义了 UNREFERENCED_PARAMETER:
#define UNREFERENCED_PARAMETER(P) {(P) = (P);}
所以你可以这样做:
#include <windows.h>
#include <stdio.h>
int main(int argc, char **argv) {
UNREFERENCED_PARAMETER(argc);
puts(argv[1]);
return 0;
}
或在 Windows 之外:
#include <stdio.h>
#define UNREFERENCED_PARAMETER(P) {(P) = (P);}
int main(int argc, char **argv) {
UNREFERENCED_PARAMETER(argc);
puts(argv[1]);
return 0;
}
operator=
可能有副作用。
不定期副业成功案例分享
main
的情况下,您可以完全省略参数。和return
声明,就此而言。main
的return 0
,但几乎总是在生产代码中编写自记录return EXIT_SUCCESS
。 这是的好习惯!