看看这个假设的头文件:
template <class T>
class HungryHippo {
public:
void ingest(const T& object);
private:
...
}
现在,对于
HungryHippo<string>
来说,您想要 ingest
对字符串的引用是有道理的——复制字符串可能会非常昂贵!但对于 HungryHippo<int>
来说,它就没那么有意义了。直接传递 int
可能非常便宜(大多数编译器会在寄存器中完成),但传递对 int
的引用是额外不必要的间接级别。这也适用于返回值。
有没有什么方法可以向编译器建议“嘿,我不会修改参数,所以you决定是按值传递还是按引用传递,具体取决于你认为哪个更好”?
一些可能相关的事情:
template <class T, bool PassByValue> class HungryHippo
然后专门研究 PassByValue
来手动伪造这种效果。如果我想变得更花哨,我什至可以根据 PassByValue
和 sizeof(T)
推断 std::is_trivially_copyable<T>
。无论哪种方式,当实现看起来几乎相同时,这都是大量额外的工作,并且我怀疑编译器在决定是否按值传递方面可以比我做得更好。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++ 引用语义强加的不变量允许编译器简单地替换整个函数体中的值(如果它是胜利的话)。如果不是,最坏情况的开销是函数序言中的一个指向参数的指针取消引用。