我的代码如何区分编译时常量和变量?
这是我的问题。我有一个 BINARY_FLAG
宏:
#define BINARY_FLAG( n ) ( static_cast<DWORD>( 1 << ( n ) ) )
可以像这样使用(“常量”场景):
static const SomeConstant = BINARY_FLAG( 5 );
或像这样(“变量”场景):
for( int i = 0; i < 10; i++ ) {
DWORD flag = BINARY_FLAG( i );
// do something with the value
}
这个宏根本不是万无一失的 - 人们可以通过 -1
或 34
那里最多会出现警告,但行为将是未定义的。我想让它更加万无一失。
对于常量场景,我可以使用模板:
template<int Shift> class BinaryFlag {
staticAssert( 0 <= Shift && Shift < sizeof( DWORD) * CHAR_BIT );
public:
static const DWORD FlagValue = static_cast<DWORD>( 1 << Shift );
};
#define BINARY_FLAG( n ) CBinaryFlag<n>::FlagValue
但这不适用于“变量”场景 - 我需要一个运行时断言:
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)
后者很好,但没有编译时检查。当然,我希望尽可能进行编译时检查,否则进行运行时检查。在任何时候,我都希望运行时开销尽可能小,因此当可以进行编译时检查时,我不希望进行函数调用(可能不会被内联)。
我看到这个问题,但看起来并不是同一个问题。
是否有某种构造允许在两者之间进行交替,具体取决于作为标志号传递的表达式是编译时常量还是变量?
Here's my problem. I have a BINARY_FLAG
macro:
#define BINARY_FLAG( n ) ( static_cast<DWORD>( 1 << ( n ) ) )
Which can be used either like this ("constant" scenario):
static const SomeConstant = BINARY_FLAG( 5 );
or like this ("variable" scenario):
for( int i = 0; i < 10; i++ ) {
DWORD flag = BINARY_FLAG( i );
// do something with the value
}
This macro is not foolproof at all - one can pass -1
or 34
there and there will at most be a warning yet behavior will be undefined. I'd like to make it more foolproof.
For the constant scenario I could use a template:
template<int Shift> class BinaryFlag {
staticAssert( 0 <= Shift && Shift < sizeof( DWORD) * CHAR_BIT );
public:
static const DWORD FlagValue = static_cast<DWORD>( 1 << Shift );
};
#define BINARY_FLAG( n ) CBinaryFlag<n>::FlagValue
but this will not go for the "variable" scenario - I'd need a runtime assertion there:
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)
The latter is good, but has no compile-time checks. Of course, I'd like a compile-time check where possible and a runtime check otherwise. At all times I want as little runtime overhead as possible so I don't want a function call (that maybe won't be inlined) when a compile-time check is possible.
I saw this question, but it doesn't look like it is about the same problem.
Is there some construct that would allow to alternate between the two depending on whether the expression passed as a flag number is a compile-time constant or a variable?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这比你想象的要简单:)
让我们看看:
我没有使用 MSVC,但我用 Mingw GCC 4.5 编译:
第一个方法的结果代码如下所示:
第二个:
看到了吗?编译器足够聪明,可以为你做这件事。不需要宏,不需要元编程,不需要 C++0x。就这么简单。
检查 MSVC 是否做同样的事情...但是看 - 编译器计算常量表达式并删除未使用的条件分支真的很容易。如果您想确定,请检查它...但一般情况下- 相信你的工具。
This is simpler than you think :)
Let's have a look:
I don't use MSVC, but I compiled with Mingw GCC 4.5:
The resulting code for first method looks like:
And the second:
See? The compiler is smart enough to do it for you. No need for macros, no need for metaprogramming, no need for C++0x. As simple as that.
Check if MSVC does the same... But look - it's really easy for the compiler to evaluate a constant expression and drop the unused conditional branch. Check it if you want to be sure... But generally - trust your tools.
不可能将参数传递给宏或函数并确定它是编译时常量还是变量。
最好的方法是使用编译时代码
#define BINARY_FLAG(n)
并将该宏放置在各处,然后进行编译。您将在n
运行时的地方收到编译器错误。现在,您可以将这些宏替换为运行时宏BINARY_FLAG_RUNTIME(n)
。这是唯一可行的办法。It's not possible to pass an argument to a macro or function and determine if it's compile time constant or a variable.
The best way is that you
#define BINARY_FLAG(n)
with compile time code and place that macro everywhere and then compile it. You will receive compiler-errors at the places wheren
is going to be runtime. Now, you can replace those macros with your runtime macroBINARY_FLAG_RUNTIME(n)
. This is the only feasible way.我建议你使用两个宏。
BINARY_FLAG
CONST_BINARY_FLAG
这将使您的代码更容易被其他人掌握。在撰写本文时,您确实知道它是否是 const。
而且我在任何情况下都不会担心运行时开销。你的优化器,至少在 VS 中,会为你解决这个问题。
I suggest you use two macros.
BINARY_FLAG
CONST_BINARY_FLAG
That will make your code easier to grasp for others. You do know, at the time of writing, if it is a const or not.
And I would in no case worry about runtime overhead. Your optimizer, at least in VS, will sort that out for you.