我可以让C++编译器决定是按值传递还是按引用传递吗
Can I let the C++ compiler decide whether to pass-by-value or pass-by-reference?
看看这个假设的头文件:
template <class T>
class HungryHippo {
public:
void ingest(const T& object);
private:
...
}
现在,对于HungryHippo<string>
,您希望ingest
引用字符串是有道理的——复制字符串可能非常昂贵!但对于HungryHippo<int>
来说,这就没那么有意义了。直接传递int
可能非常便宜(大多数编译器会在寄存器中进行),但传递对int
的引用是一种额外的不必要的间接级别。这一切同样适用于返回值。
有没有办法向编译器建议"嘿,我不会修改参数,所以你决定是通过值传递还是通过引用传递,这取决于你认为什么更好"?
一些可能相关的事情:
- 我可以通过编写
template <class T, bool PassByValue> class HungryHippo
然后专门处理PassByValue
来手动伪造这种效果。如果我想得到真正的幻想,我甚至可以根据sizeof(T)
和std::is_trivially_copyable<T>
推断出PassByValue
。无论哪种方式,当实现看起来几乎相同时,这都是大量的额外工作,我怀疑编译器在决定是否传递值方面比我做得更好 libc++项目似乎通过内联许多函数来解决这个问题,这样编译器就可以进行更高级别的选择,但在这种情况下,假设如注释中所述,默认情况下,所有模板函数都是ingest
的实现相当复杂,不值得内联inline
boost::call_traits
标头正是处理这个问题。在这里查看。
具体而言,call_traits<T>::param_type
选项包括以下描述:
如果
T
是小型内置类型或指针,则定义param_type
作为T const
而不是T const&
。这可以提高编译器优化函数体中的循环(如果它们依赖)对于传递的参数,传递的参数的语义为否则保持不变(需要部分专业化)。
在您的情况下,您可以如下定义ingest
:
template <class T>
class HungryHippo {
public:
void ingest(call_traits<T>::param_type object);
// "object" will be passed-by-value for small
// built-in types, but passed as a const reference
// otherwise
private:
...
};
我不确定这是否真的会对你的实际代码/编译器组合产生很大影响。和往常一样,你必须运行一些实际的基准测试,看看会发生什么。。。
虽然像boost提到的call_traits<T>
这样的技巧在这种情况下会做他们声称要做的事情,但我认为你假设编译器在最重要的情况下还没有进行这种优化。毕竟,这是微不足道的。如果接受const T&
和sizeof(T) <= sizeof(void*)
,C++引用语义强加的不变量允许编译器简单地替换整个函数体中的值(如果成功的话)。如果不是,那么最坏情况下的开销是指向函数prolog中arg取消引用的一个指针。
- 何时应通过引用传递矢量参数而不是按值传递矢量参数?
- 棘手的按值传递和按引用递归问题传递
- 不同于按值传递和常量引用传递的程序集
- 按值传递变量与按引用传递变量具有相同的结果
- 为什么按值传递QStringView比引用常量更快?
- 获取 std::函数以推断按引用传递/按值传递
- C++/11 auto 关键字是在更有效时推导参数进行按引用传递,还是始终按值传递?
- 按值和按引用差异的函数模板
- 布尔值是通过引用传递的,但我仍然在 cpp 中遇到编译错误
- 运算符 = 回合侧一个按值秒按引用
- 按值或常量引用传递函数
- 按值与按引用读取C++向量
- 修改向量的元素(按值、按引用) 函数C++
- 按值或常量引用传递
- 函数返回值与修改引用传递的值
- 通过构造函数中的值或常量引用传递的参数
- 返回值或修改引用传递的参数是否更快?
- 按值将类型结构传递给函数,错误:声明"average"中的两个或多个数据类型!!-
- c++中的函数按值或按引用返回
- 哪个更好:按值或按常量引用返回std::string