[英]Compile-time with mixed const/non-const ternary operator
考虑以下示例:
template<int X> class MyClass
{
public:
MyClass(int x) {_ncx = x;}
void test()
{
for (unsigned int i = 0; i < 1000000; ++i) {
if ((X < 0) ? (_cx > 5) : (_ncx > 5)) {
/* SOMETHING */
} else {
/* SOMETHING */
}
}
}
protected:
static const int _cx = (X < 0) ? (-X) : (X);
int _ncx;
};
我的问题是:MyClass <-6> :: test()和MyClass <6> :: test()会有不同的速度吗?
我希望是这样,因为如果模板参数为负, if
可以在编译时评估测试中的if
in函数,但是我不确定如果有编译时事件并且非编译时,编译器的行为是什么?三元运算符中的编译时事物(这里就是这种情况)。
注意:这是一个纯粹的“理论”问题。 如果非空概率为“是”,则将使用此类编译时模板参数为我的代码实现某个类,否则,我将仅提供运行时版本。
将条件移到循环外:
...
if ((X < 0) ? (_cx > 5) : (_ncx > 5)) {
for (unsigned int i = 0; i < 1000000; ++i) {
/* SOMETHING */
}
} else {
for (unsigned int i = 0; i < 1000000; ++i) {
/* SOMETHING */
}
}
...
这样一来,您就不必依赖编译器优化来删除未使用的代码。 如果编译器没有删除条件的未使用部分,则只需为条件分支支付一次,而不是每次循环都需要。
对于我的编译器(OS X上为clang ++ v2.9),编译此相似但不相同的代码:
void foo();
void bar();
template<int N>
void do_something( int arg ) {
if ( N<0 && arg<0 ) { foo(); }
else { bar(); }
}
// Some functions to instantiate the templates.
void one_fn(int arg) {
do_something<1>(arg);
}
void neg_one_fn(int arg) {
do_something<-1>(arg);
}
这将使用clang++ -S -O3
生成以下程序集。
显然,第一个功能组件只有对bar
的调用。
.globl __Z6one_fni
.align 4, 0x90
__Z6one_fni: ## @_Z6one_fni
Leh_func_begin0:
pushl %ebp
movl %esp, %ebp
popl %ebp
jmp __Z3barv ## TAILCALL
Leh_func_end0:
如果调用bar
或foo
则第二个函数已简化为一个简单的函数。
.globl __Z10neg_one_fni
.align 4, 0x90
__Z10neg_one_fni: ## @_Z10neg_one_fni
Leh_func_begin1:
pushl %ebp
movl %esp, %ebp
cmpl $0, 8(%ebp)
jns LBB1_2 ## %if.else.i
popl %ebp
jmp __Z3foov ## TAILCALL
LBB1_2: ## %if.else.i
popl %ebp
jmp __Z3barv ## TAILCALL
Leh_func_end1:
因此,您可以看到编译器内联了模板,然后在可能的情况下优化了分支。 因此,您希望进行的转换确实发生在当前的编译器中。 我也从旧的g ++ 4.0.1编译器中获得了相似的结果(但汇编过程不太清晰)。
我认为此示例与您的初始情况不太相似(因为它不涉及三元运算符),因此我将其更改为:(获得相同的结果)
template<int X>
void do_something_else( int _ncx ) {
static const int _cx = (X<0) ? (-X) : (X);
if ( (X < 0) ? (_cx > 5) : (_ncx > 5)) {
foo();
} else {
bar();
}
}
void a(int arg) {
do_something_else<1>(arg);
}
void b(int arg) {
do_something_else<-1>(arg);
}
这生成了程序集
这仍然包含分支。
__Z1ai: ## @_Z1ai
Leh_func_begin2:
pushl %ebp
movl %esp, %ebp
cmpl $6, 8(%ebp)
jl LBB2_2 ## %if.then.i
popl %ebp
jmp __Z3foov ## TAILCALL
LBB2_2: ## %if.else.i
popl %ebp
jmp __Z3barv ## TAILCALL
Leh_func_end2:
分支被优化掉了。
__Z1bi: ## @_Z1bi
Leh_func_begin3:
pushl %ebp
movl %esp, %ebp
popl %ebp
jmp __Z3barv ## TAILCALL
Leh_func_end3:
这可能取决于编译器的智能程度。 我建议您编写一个基准测试程序以在您的环境中对其进行测试,以确保确定。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.