模板传递值或const引用或...?

Rom*_*n L 7 c++ templates pass-by-reference pass-by-value

我可以用这种方式编写模板化函数

template<class T> void f(T x) {...}
Run Code Online (Sandbox Code Playgroud)

或者这样

template<class T> void f(T const& x) {...}
Run Code Online (Sandbox Code Playgroud)

我猜第二个选项可以更加优化,因为它明确地避免了副本,但我怀疑它也可能因某些特定类型T(例如仿函数?)而失败.那么,什么时候应该使用第一个选项,何时使用第二个选项?还有这个boost::call_traits<T>::param_typeboost::reference_wrapper那个在我之前的问题的答案,但人们不到处使用它们,是吗?这有经验法则吗?谢谢.

Jam*_*lis 11

这有经验法则吗?

关于何时使用按引用传递与按值传递的相同的一般规则适用.

如果您希望T始终是一个数字类型或复制非常便宜的类型,那么您可以按值获取参数.如果你打算将参数的副本复制到函数中的局部变量中,那么你应该按值来获取它,以帮助编译器完全不需要创建副本.

否则,请参考参数.对于复制成本低廉的类型,它可能更昂贵,但对于其他类型,它会更快.如果您发现这是一个性能热点,您可以为不同类型的参数重载函数,并为每个参数执行正确的操作.

  • @ 7vies:不是真的;唯一的“问题”是,您不仅要考虑一种类型,还必须决定使用模板的那组类型有意义。 (2认同)
  • @ 7vies:`boost :: call_traits`对你不会有帮助,因为`param_type`是任何用户定义类型的const引用(因此也是所有类类型).STL中的假设是函数对象复制起来很便宜; 如果你有一个昂贵的复制功能对象,"正确的解决方案"是使复制成本更低,如果可能的话,或者编写一个使复制更便宜的包装器. (2认同)

fre*_*low 6

我怀疑它也可能因某些特定类型而失败

通过引用传递给const是唯一一个"永不"失败的传递机制.它没有提出任何要求T,它接受左值和右值作为参数,并允许隐式转换.


小智 5

你不会唤醒死者,但会遇到类似的问题,这里有一些示例代码,展示了如何使用 C++11 的类型特征来推断参数是应该通过值传递还是引用传递:

#include <iostream>
#include <type_traits>

template<typename key_type>
class example
{
    using parameter_type = typename std::conditional<std::is_fundamental<key_type>::value, key_type, key_type&>::type;

 public:
  void function(parameter_type param)
  {
      if (std::is_reference<parameter_type>::value)
      {
          std::cout << "passed by reference" << std::endl;
      } else {
          std::cout << "passed by value" << std::endl;
      }
  }
};

struct non_fundamental_type
{
    int one;
    char * two;
};

int main()
{
  int one = 1;
  non_fundamental_type nft;

  example<int>().function(one);
  example<non_fundamental_type>().function(nft);

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

希望它可以帮助其他有类似问题的人。