模板化的数学函数应该采用值还是const引用?

时间:2016-10-12 21:24:34

标签: c++ math const-reference pass-by-const-reference

假设我想实现一些简单的数学函数;例如,假设它是(C ++ 17)std::clamp的重新实现:此函数采用数字,下限和上限,并将数字设置为其中一个边界(如果超出它们定义的范围) 。如果它是具体的数字类型,比如int,我会写:

constexpr int clamp(int x, int lower_bound, int upper_bound)
{
    return x < lower_bound ? lower_bound : ( upper_bound < x ? upper_bound : x );
}

但是如果它是一个模板,我看到sample implementation可能是标准将使用的const&而不是值。因此,使引用更简单,例如:

template <typename T>
constexpr T clip(const T& x, const T& lower_bound, const T& upper_bound)
{
    return x < lower_bound ? lower_bound : ( upper_bound < x ? upper_bound : x );
}

我的问题是:

  • 对于T的简单数字类型,对const引用有什么好处吗?
  • 同上,对于包含单个数字作为数据成员的抽象事物(例如std::chrono个持续时间)的类型?
  • 为什么(并且根本不是)在任何相对简单的(constexpr?),无副作用数学的一般情况下取一个const&然后一个值更好的主意功能?

注意:

  • 我知道当你拥有某种k维向量类型,或const& s和其他类似数字类型时,boost::rational可能会开始有意义;但即使这样,编译器也不会优化复制吗?
  • 询问任何C ++函数以及它是否应该按值获取参数,这显然是一个坏主意。

2 个答案:

答案 0 :(得分:3)

  
      
  • 对于T这些简单的数字类型,使用const引用是否有任何好处?
  •   

没有

  
      
  • 同上,对于包含单个数字作为数据成员的抽象事物(例如std::chrono个持续时间)的类型?
  •   

没有

  
      
  • 为什么在任何相对简单的(constexpr?),无副作用的数学运算的一般情况下,取一个const&而不是一个值更好的想法?功能?
  •   

想象一下使用动态分配的bigint类型;复制这种类型是很昂贵的。

  
      
  • 编译器不会优化复制吗?
  •   

只有当它能证明复制值没有副作用时,除非编译器看到所有涉及的代码,否则很难做到这一点。 (所以,如果你的bigint使用,比方说,GMP,你运气不好。)

答案 1 :(得分:2)

  

对于T这些简单的数字类型,获取const引用是否有任何好处?

不,我不这么认为,但也没有惩罚。

  

同上,对于包含单个数字作为数据成员的某些抽象事物的类型(例如std::chrono duration)?

同上。

  

为什么在一般情况下采用const&然后是值更好的想法(并且根本就是这样)?

标准库算法不仅适用于基本类型,还适用于用户定义的类型,复制起来可能并不便宜。对于这些类型,使用const&可以避免复制的惩罚,同时不会损害基本类型的用法。