模板化数学函数应该采用值还是 const 引用?
Should templated math functions take values or const references?
假设我想实现一些简单的数学函数;例如,假设它是 (C++17's) 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&
比取一个值更好(而且根本不是) -ish 函数?
备注:
- 我意识到当你有某种 k 维向量类型或
boost::rational
s 和其他类似数字的类型时,采用 const&
可能会开始有意义;但即便如此,编译器不会优化复制吗?
- 我不是询问任何任意 C++ 函数以及它是否应该按值获取其参数,这显然不是一个好主意。
Is there any benefit to taking a const reference, for T
's which are simple numeric types?
不,我不这么认为,但也没有处罚。
Ditto, for types which are some abstract thing wrapping a single number as a data member (e.g. a std::chrono duration
)?
同上。
Why is it (and is it at all) a better idea to take a const&
then a value in the general case?
标准库算法不仅适用于基本类型,也适用于用户定义的类型,复制这些类型可能并不便宜。对于这些类型,使用 const&
可以避免复制的惩罚,同时不会损害基本类型的用法。
- Is there any benefit to taking a const reference, for
T
's which are simple numeric types?
没有
- Ditto, for types which are some abstract thing wrapping a single number as a data member (e.g. a
std::chrono
duration)?
没有
- Why is it (and is it at all) a better idea to take a
const&
than a value in the general case of any relatively-simple, (constexpr?), side-effect-free math-ish function?
想象一个使用动态分配的 bigint 类型;复制这样的类型很昂贵。
- Wouldn't a compiler optimize the copying away?
只有它能证明复制值没有副作用,这很难做到,除非涉及的所有代码对编译器都是可见的。 (所以,如果你的 bigint 使用 GMP,那你就不走运了。)
假设我想实现一些简单的数学函数;例如,假设它是 (C++17's) 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&
比取一个值更好(而且根本不是) -ish 函数?
备注:
- 我意识到当你有某种 k 维向量类型或
boost::rational
s 和其他类似数字的类型时,采用const&
可能会开始有意义;但即便如此,编译器不会优化复制吗? - 我不是询问任何任意 C++ 函数以及它是否应该按值获取其参数,这显然不是一个好主意。
Is there any benefit to taking a const reference, for
T
's which are simple numeric types?
不,我不这么认为,但也没有处罚。
Ditto, for types which are some abstract thing wrapping a single number as a data member (e.g. a
std::chrono duration
)?
同上。
Why is it (and is it at all) a better idea to take a
const&
then a value in the general case?
标准库算法不仅适用于基本类型,也适用于用户定义的类型,复制这些类型可能并不便宜。对于这些类型,使用 const&
可以避免复制的惩罚,同时不会损害基本类型的用法。
- Is there any benefit to taking a const reference, for
T
's which are simple numeric types?
没有
- Ditto, for types which are some abstract thing wrapping a single number as a data member (e.g. a
std::chrono
duration)?
没有
- Why is it (and is it at all) a better idea to take a
const&
than a value in the general case of any relatively-simple, (constexpr?), side-effect-free math-ish function?
想象一个使用动态分配的 bigint 类型;复制这样的类型很昂贵。
- Wouldn't a compiler optimize the copying away?
只有它能证明复制值没有副作用,这很难做到,除非涉及的所有代码对编译器都是可见的。 (所以,如果你的 bigint 使用 GMP,那你就不走运了。)