Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 我的代码如何区分编译时常量和变量?_C++_Templates_Visual C++_Macros_Metaprogramming - Fatal编程技术网

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是否也这样做…但是查看-编译器很容易计算常量表达式并删除未使用的条件分支。如果您想确定,请检查它…但一般来说,请信任您的工具。

断言(0
shift
此处?另外,如果您将参数传递给
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