10

我可以这样写一个模板函数

template<class T> void f(T x) {…}

或者这样

template<class T> void f(T const& x) {…}

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

4

5 回答 5

13

这有经验法则吗?

适用于何时使用按引用传递和按值传递的相同一般规则。

如果您希望T始终是数字类型或复制起来非常便宜的类型,那么您可以按值获取参数。如果无论如何您要将参数的副本复制到函数中的局部变量中,那么您应该按值获取它以帮助编译器删除实际上不需要制作的副本。

否则,通过引用获取参数。对于复制成本较低的类型,它可能会更昂贵,但对于其他类型,它会更快。如果您发现这是一个性能热点,您可以为不同类型的参数重载该函数,并为每个参数做正确的事情。

于 2011-02-02T16:20:41.083 回答
7

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

通过引用到常量传递是唯一“从不”失败的传递机制。它对 没有任何要求T,它接受左值和右值作为参数,并且允许隐式转换。

于 2011-02-02T16:46:33.463 回答
5

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

#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;
}

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

于 2015-01-22T10:01:29.970 回答
0

除了 James McNellis 写的内容之外,我只想补充一点,您可以针对引用类型专门化您的模板(例如像这样

于 2011-02-02T16:28:11.860 回答
0

boost::traits具有基于 T 选择“最佳”类型的类型特征:

call_traits<T>::param_type

如前所述,不存在特定于模板的问题。

于 2011-02-02T16:37:06.057 回答