c++ - 我的代码如何区分编译时常量和变量?

标签 c++ templates visual-c++ macros metaprogramming

这是我的问题。我有一个 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
}

这个宏根本不是万无一失的 - 可以在那里传递 -134 最多会有一个警告,但行为将是未定义的。我想让它更简单。

对于常量场景,我可以使用模板:

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)

后者很好,但没有编译时检查。当然,我希望尽可能进行编译时检查,否则进行运行时检查。在任何时候我都希望尽可能少的运行时开销,所以我不希望在可以进行编译时检查时进行函数调用(可能不会内联)。

我看到了this question , 但它看起来不像是同一个问题。

是否有某种构造允许根据作为标志编号传递的表达式是编译时常量还是变量而在两者之间交替?

最佳答案

这比你想象的要简单:)

让我们看看:

#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);
}

我不使用 MSVC,但我使用 Mingw GCC 4.5 编译:

g++ -c -S -O3 08042.cpp

第一种方法的结果代码如下:

__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

看到了吗?编译器足够聪明,可以为你做这件事。不需要宏,不需要元编程,不需要 C++0x。就这么简单。

检查 MSVC 是否做同样的事情...但是看 - 编译器很容易评估常量表达式并删除未使用的条件分支。如果您想确定,请检查它。 . 但一般来说 - 相信你的工具。

关于c++ - 我的代码如何区分编译时常量和变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6939103/

相关文章:

c++ - 如何在另一台计算机上运行调试文件?

c++ - Boost.Preprocessor 是否可以实现二维序列?

c++ - 'ClassName' 和 'ClassInstance' 未在此范围内声明

c++ - 我应该如何编写一个像 MPL 中那样工作的元函数?

javascript - 如何在 backbone.js 中使用 subview

模板类中的 C++ 模板 static const 成员变量

c++ - 在 C++ 中实现 Rodrigues 的旋转公式时遇到问题

c++ - 参数检查

c++ - 是否可以在编译时打印出 C++ 类的大小?

javascript - 在 C++ 中继承 IObjectSafetyImpl 以实现安全的 javascript activex 控件