[英]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.