我想写一个模板函数
template <typename T>
void f( T v );
如果它足够小,v
它将通过值传递,否则通过引用到常量。
编译器可以足够聪明地在没有任何模板魔法的情况下做正确的事情,特别是如果函数f
可以内联。我总是会实现f
为
template <typename T>
void f(const T& v);
如果副本更便宜,请相信编译器会将其转换为副本。
这是一个例子:
extern volatile int k;
extern volatile int m;
static void f(const int& j) noexcept { // or f(const int j)
for (int i=0; i<j; ++i) {
m = i;
}
}
void g() noexcept {
int j = k;
f(j);
}
我跑clang++ -O3 -std=c++11 -S -emit-llvm filename.cpp
了,生成的程序集(据我所知)是一样的。
通过引用传递:
@k = external global i32
@m = external global i32
; Function Attrs: nounwind uwtable
define void @_Z1gv() #0 {
entry:
%0 = load volatile i32* @k, align 4, !tbaa !0
%cmp3.i = icmp sgt i32 %0, 0
br i1 %cmp3.i, label %for.body.i, label %_ZL1fRKi.exit
for.body.i: ; preds = %entry, %for.body.i
%i.04.i = phi i32 [ %inc.i, %for.body.i ], [ 0, %entry ]
store volatile i32 %i.04.i, i32* @m, align 4, !tbaa !0
%inc.i = add nsw i32 %i.04.i, 1
%exitcond = icmp eq i32 %inc.i, %0
br i1 %exitcond, label %_ZL1fRKi.exit, label %for.body.i
_ZL1fRKi.exit: ; preds = %for.body.i, %entry
ret void
}
按值传递:
@k = external global i32
@m = external global i32
; Function Attrs: nounwind uwtable
define void @_Z1gv() #0 {
entry:
%0 = load volatile i32* @k, align 4, !tbaa !0
%cmp3.i = icmp sgt i32 %0, 0
br i1 %cmp3.i, label %for.body.i, label %_ZL1fi.exit
for.body.i: ; preds = %entry, %for.body.i
%i.04.i = phi i32 [ %inc.i, %for.body.i ], [ 0, %entry ]
store volatile i32 %i.04.i, i32* @m, align 4, !tbaa !0
%inc.i = add nsw i32 %i.04.i, 1
%exitcond.i = icmp eq i32 %inc.i, %0
br i1 %exitcond.i, label %_ZL1fi.exit, label %for.body.i
_ZL1fi.exit: ; preds = %for.body.i, %entry
ret void
}
如果f
没有内联,那么程序集是不同的。