C++ C++;语言模板问题
下面是一个小测试用例,演示了我试图用C++中的模板解决的一个问题:C++ C++;语言模板问题,c++,templates,C++,Templates,下面是一个小测试用例,演示了我试图用C++中的模板解决的一个问题: template<typename T> void unused(T const &) { /* Do nothing. */ } int main() { volatile bool x = false; unused(!x); // type of "!x" is bool } 这里的目标是让未使用的禁止在优化代码中出现未使用的变量警告。我有一个宏,它执行断言检查,在优化代码中断言消失,但
template<typename T>
void
unused(T const &) {
/* Do nothing. */
}
int main() {
volatile bool x = false;
unused(!x); // type of "!x" is bool
}
这里的目标是让未使用的禁止在优化代码中出现未使用的变量警告。我有一个宏,它执行断言检查,在优化代码中断言消失,但我希望断言表达式中的任何变量都保持引用状态,这样我就不会只在优化代码中收到未使用的变量警告。在unused()模板函数的定义中,我使用了一个引用,这样就不会无意中运行复制构造函数代码,这样编译器就可以完全省略对unused的调用
对于感兴趣的人,断言宏如下所示:
#ifdef NDEBUG
# define Assert(expression) unused(expression)
#else // not NDEBUG
# define Assert(expression) \
{ \
bool test = (expression); \
\
if (!test) { \
if (StopHere(__LINE__, __FILE__, __PRETTY_FUNCTION__, \
#expression, false)) { \
throw Exit(-1); /* So that destructors are run. */ \
} \
} \
}
#endif // else not NDEBUG
template<typename T>
void
unused(T const) {
/* Do nothing. */
}
#define UNUSED(x) ((void)x)
#if defined ASSERT_ENABLED
#define TEST(test) (!(test)) ? assert_failed(# test, __FILE__, __LINE__) : (void)0
#else
#define TEST(ignore) ((void)0)
#endif
对于上述测试用例,我可以通过添加另一个类似的未使用函数来消除错误,如下所示:
#ifdef NDEBUG
# define Assert(expression) unused(expression)
#else // not NDEBUG
# define Assert(expression) \
{ \
bool test = (expression); \
\
if (!test) { \
if (StopHere(__LINE__, __FILE__, __PRETTY_FUNCTION__, \
#expression, false)) { \
throw Exit(-1); /* So that destructors are run. */ \
} \
} \
}
#endif // else not NDEBUG
template<typename T>
void
unused(T const) {
/* Do nothing. */
}
#define UNUSED(x) ((void)x)
#if defined ASSERT_ENABLED
#define TEST(test) (!(test)) ? assert_failed(# test, __FILE__, __LINE__) : (void)0
#else
#define TEST(ignore) ((void)0)
#endif
所以我的问题是,如何更改unused()或重载它,使其满足以下要求:
-William为什么不完全跳过模板,使用省略号呢
inline void unused (...) { /* do nothing */ }
你为什么要通过
!如果表达式的值无关紧要,则readWriteActivated
而不是readWriteActivated
?实现此目的的一种常见(且更简单)方法是将结果强制转换为void
(void) x;
其中x是一些未引用的值。如果要抑制未使用变量警告,为什么将其称为
未使用(!readWriteActivated)?你为什么不能叫它
未使用(读写激活); 并将代码设置为
template<typename T>
void UnUsed(const T& )
{
}
模板
无效未使用(常数T&)
{
}
如需更多参考资料,请参阅Herb Sutter的博客文章
编辑:删除函数中的参数名称。这适用于
未使用(!readWriteActivated);还有。我见过的最好的解决方案是:
#ifdef NDEBUG
# define Assert(expression) unused(expression)
#else // not NDEBUG
# define Assert(expression) \
{ \
bool test = (expression); \
\
if (!test) { \
if (StopHere(__LINE__, __FILE__, __PRETTY_FUNCTION__, \
#expression, false)) { \
throw Exit(-1); /* So that destructors are run. */ \
} \
} \
}
#endif // else not NDEBUG
template<typename T>
void
unused(T const) {
/* Do nothing. */
}
#define UNUSED(x) ((void)x)
#if defined ASSERT_ENABLED
#define TEST(test) (!(test)) ? assert_failed(# test, __FILE__, __LINE__) : (void)0
#else
#define TEST(ignore) ((void)0)
#endif
它是可移植的,并成功抑制警告
编辑:
既然您已经说过这更像是一个断言,那么您可能应该这样做:
#ifdef NDEBUG
# define Assert(expression) unused(expression)
#else // not NDEBUG
# define Assert(expression) \
{ \
bool test = (expression); \
\
if (!test) { \
if (StopHere(__LINE__, __FILE__, __PRETTY_FUNCTION__, \
#expression, false)) { \
throw Exit(-1); /* So that destructors are run. */ \
} \
} \
}
#endif // else not NDEBUG
template<typename T>
void
unused(T const) {
/* Do nothing. */
}
#define UNUSED(x) ((void)x)
#if defined ASSERT_ENABLED
#define TEST(test) (!(test)) ? assert_failed(# test, __FILE__, __LINE__) : (void)0
#else
#define TEST(ignore) ((void)0)
#endif
除非定义了ASSERT\u ENABLED
,否则不会生成代码,并且不会生成有关未使用变量的警告。libc中的assert
宏就是这样工作的
我想问题在于,变量只在断言中使用,这是一种很糟糕的方法,无法满足您的需要。为什么不将其标记为未使用,并单独使用断言宏,这样很明显,该变量实际上没有用于任何用途,但您仍然可以获得调试生成断言。只需单独解决问题。更改未使用的定义:
inline void unused(bool) {}
因为您已经需要一个需要转换为bool的表达式,所以这将进行转换,而不进行其他任何操作。内联允许编译器进行优化,包括在表达式没有副作用的情况下(但您必须进行测试才能确切知道在复杂情况下会发生什么)
此外,这修复了大多数断言宏的一个常见问题:如果表达式确实有副作用,则将始终对其进行计算。(这取决于使用情况,可能非常好,也可能非常坏。)查尔斯·尼科尔森建议这样做来标记未使用的变量,原因如下: 简短的版本是。。。sizeof不会对表达式求值,但在本上下文中看到该表达式时,编译器仍将其视为“已使用”
我相信这满足了您的所有4个条件,特别是因为sizeof()可以接受任何有效的表达式,并且因为表达式不会被计算(因此不会生成任何代码)。正如Johannes在评论中所说,您遇到了编译器错误。您可以通过显式转换为
bool
来解决此问题:
unused( bool( !readWriteActivated) ); // add bool() to any (!volatile_bool_var)
旧答案(但仍然不是一个坏主意) 如果我回忆一下const volatile限定规则,那么您所需要的就是进一步限定虚拟变量。本质上,您只需要在声明的类型vP中重复错误消息
template<typename T>
void
unused(T const volatile &) { // only change is to add "volatile"
/* Do nothing. */
}
模板
无效的
未使用(T const volatile&){//唯一的更改是添加“volatile”
/*什么也不做*/
}
另外,很高兴您将
常量
放在类型之后,即它所属的位置。编译器警告与已使用或未使用无关。您正在向不接受volatile引用的函数传递volatile变量readWriteActivated。尝试常量转换。这是一个错误:
在unused()级别没有解决方法。相反,可以通过在调用unused()之前引入一个临时变量来解决每次出现的问题:
模板
无效的
未使用(T常数&){
/*什么也不做*/
}
int main(){
挥发性bool x=假;
bool avoidGCC42655=!x;//类型为bool的“!x”
未使用(避免GCC42655);
}
拒绝第一个代码段看起来像是GCC错误:类型为!一些易失性bool
是bool
而不是volatile bool
——因此T
应该被推断为bool
,而不是volatile bool
。请注意,非类类型的rvalue从来都不是const/volatile限定的。报告说:对我来说,这看起来像是Herb Sutter在他的博客中提到的重复,顺便说一句,你在使用哪个编译器?可能是个bug,但如果他没有调用unused(readWriteActivated)
,那听起来就像他的意图一样。g++v3.4.6,但是这些版本中的错误也很明显:4.0.0 4.1.0 4.2.0 4.3.0 4.4.0 4.5.0然后在前面抛出一个&
。可变函数必须具有