C++ 我的代码如何区分编译时常量和变量?
这是我的问题。我有一个C++ 我的代码如何区分编译时常量和变量?,c++,templates,visual-c++,macros,metaprogramming,C++,Templates,Visual C++,Macros,Metaprogramming,这是我的问题。我有一个二进制\u标志宏: #define BINARY_FLAG( n ) ( static_cast<DWORD>( 1 << ( n ) ) ) 或者像这样(“可变”场景): 但这不适用于“变量”场景-我需要一个运行时断言: inline DWORD ProduceBinaryFlag( int shift ) { assert( 0 <= shift && shift < sizeof( DWORD) * CHA
二进制\u标志
宏:
#define BINARY_FLAG( n ) ( static_cast<DWORD>( 1 << ( n ) ) )
或者像这样(“可变”场景):
但这不适用于“变量”场景-我需要一个运行时断言:
inline DWORD ProduceBinaryFlag( int shift )
{
assert( 0 <= shift && shift < sizeof( DWORD) * CHAR_BIT );
return static_cast<DWORD>( 1 << shift );
}
#define BINARY_FLAG( n ) ProduceBinaryFlag(n)
内联DWORD ProduceBinaryFlag(int-shift)
{
assert(0我建议您使用两个宏。
二进制\u标志
常量二进制标志
这将使您的代码更容易为其他人理解。在编写代码时,您确实知道它是否为常量。
在任何情况下,我都不会担心运行时开销。您的优化器,至少在VS中,将为您排序。不可能将参数传递给宏或函数,并确定它是编译时常量还是变量
最好的方法是用编译时代码定义二进制标志(n)
,将该宏放在任何地方,然后进行编译。在n
即将运行的地方,您将收到编译器错误。现在,您可以用运行时宏二进制标志(n)替换这些宏
。这是唯一可行的方法。这比你想象的要简单:)
我们来看看,
#include <cassert>
static inline int FLAG(int n) {
assert(n>=0 && n<32);
return 1<<n;
}
int test1(int n) {
return FLAG(n);
}
int test2() {
return FLAG(5);
}
第二点:
__Z5test2v:
pushl %ebp
movl %esp, %ebp
movl $32, %eax
leave
ret
看到了吗?编译器足够聪明,可以帮你完成。不需要宏,不需要元编程,不需要C++0x。就这么简单
检查MSVC是否也这样做…但是查看-编译器很容易计算常量表达式并删除未使用的条件分支。如果您想确定,请检查它…但一般来说,请信任您的工具。
断言(0shift
此处?另外,如果您将参数传递给ProduceBinaryFlag()
在运行时,您如何在编译时进行检查?或者我遗漏了什么吗?另一个例子:const int myflag=5;BINARY\u FLAG(myflag)这个例子中的例子只使用编译时间常数的一个特殊情况。一个想法——如果你愿意假设一个支持VLAs的C++实现,那么宏可以先运行一个运行时检查,然后声明一个数组大小为正的数组,如果<代码> n< /代码>在范围内,否则为负值。如果n
是一个整型常量表达式,则如果表示大小的表达式也是一个ICE,则在编译时此操作将失败。如果n
不是常量,则运行时检查将阻止UB。由于数组很小且未使用,希望它不会有很大的成本。@iammilind:我修复了代码。嗯,是的,如果我将其传递到函数中,它就不再是编译时检查了,这是我想要避免的。在C++0x实现的当前状态下,这是不可能的。当编译器实现constexpr
时,你会有办法的。同时,我不明白为什么你的macro不好。这很好,只是我不会因为非法用例而得到编译时错误。运行时错误只会发生在某些数据集上,编译时错误会在编译时立即发生。真的。静态断言是如何实现的?有了以上内容,我们只需要一个静态断言,它将无声地编译为零如果它的参数不能在编译时计算。这可能是不可能的,因为模板参数可以是typename或常量表达式…嗯。这需要技巧!
inline DWORD ProduceBinaryFlag( int shift )
{
assert( 0 <= shift && shift < sizeof( DWORD) * CHAR_BIT );
return static_cast<DWORD>( 1 << shift );
}
#define BINARY_FLAG( n ) ProduceBinaryFlag(n)
#include <cassert>
static inline int FLAG(int n) {
assert(n>=0 && n<32);
return 1<<n;
}
int test1(int n) {
return FLAG(n);
}
int test2() {
return FLAG(5);
}
__Z5test1i:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl 8(%ebp), %ecx
cmpl $31, %ecx
ja L4
movl $1, %eax
sall %cl, %eax
leave
ret
L4:
movl $4, 8(%esp)
movl $LC0, 4(%esp)
movl $LC1, (%esp)
call __assert
.p2align 2,,3
__Z5test2v:
pushl %ebp
movl %esp, %ebp
movl $32, %eax
leave
ret