16

我想写一个模板函数

template <typename T>
void f( T v );

如果它足够小,v它将通过值传递,否则通过引用到常量。为此,我使用了一个小帮手

template <typename T, bool>
struct parameter_helper;

template <typename T>
struct parameter_helper<T, true> {
    typedef T type;
};

template <typename T>
struct parameter_helper<T, false> {
    typedef const T& type;
};

template <typename T>
struct parameter {
    typedef typename parameter_helper<T, sizeof(T) <= sizeof(void*)>::type type;
};

在过去这样我可以拥有

template <typename T>
void f( typename parameter<T>::type v );

现在,在 C++11 中:这种帮助模板是否仍然有意义,或者是否有更好的方法来实现相同的效果?是否已经有现成的模板?我查了一下<type_traits>,但没有发现任何似乎相关的东西。

4

3 回答 3

13

使用 C++11,您可以定义别名模板并节省一些输入。

template<typename T> 
using parameter_t = typename parameter<T>::type;

然后将其用作

template <typename T>
void f( parameter_t<T> v ); 

AFAIK,标准库中没有为此内置任何内容。此外,您将失去实现此类特征的模板参数推导,在我看来,这会大大降低其效用。

于 2013-07-17T19:01:26.997 回答
10

我不认为 C++11 在这方面有什么新东西,但是......

我的建议是实际内化基本规则并直接使用它们。在某些情况下,即使类型小于 4 字节,您也可能希望通过 const 引用传递(该函数将存储引用以供以后使用,尽管它不应更改访问更新值所需的字段)。

在相反的方向上,如果函数无论如何都要进行复制,您可能希望通过值传递,以便在界面中完成复制并且可以省略复制或将其更改为移动操作,从而可能降低操作成本.

于 2013-07-17T18:57:42.250 回答
4

我想写一个模板函数

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没有内联,那么程序集是不同的。

于 2013-07-17T21:19:46.703 回答