15

看看这个假设的头文件:

template <class T>
class HungryHippo {
public:
    void ingest(const T& object);
private:
    ...
}

现在,HungryHippo<string>您想要ingest引用字符串是有道理的——复制字符串可能非常昂贵!但对于 aHungryHippo<int>来说,它的意义不大。直接传递 anint可能真的很便宜(大多数编译器会在寄存器中这样做),但是传递对 an 的引用int是额外不必要的间接级别。这也适用于返回值。

有没有办法向编译器建议“嘿,我不打算修改参数,所以决定是通过值还是通过引用传递,这取决于你认为什么更好”?

一些可能相关的事情:

  • 我可以通过编写template <class T, bool PassByValue> class HungryHippo然后专注于PassByValue. 如果我想变得非常花哨,我什至可以PassByValue根据sizeof(T)and来推断std::is_trivially_copyable<T>。无论哪种方式,当实现看起来几乎相同时,这都是很多额外的工作,而且我怀疑编译器可以比我更好地决定是否通过值传递。
  • libc++项目似乎通过内联许多函数来解决这个问题,因此编译器可以向上一级做出选择,但在这种情况下,假设 的实现ingest相当复杂,不值得内联。正如评论中所解释的,所有模板函数都是inline默认的。
4

2 回答 2

8

标题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:
    ...
};

我不确定这是否会对您的实际代码/编译器组合产生很大影响。与往常一样,您必须运行一些实际的基准测试,看看会发生什么......

于 2012-11-16T00:22:56.897 回答
0

虽然提到的诸如 boost 之类的技巧call_traits<T>在这种情况下可以做到他们声称要做的事情,但我认为您假设编译器尚未在最重要的情况下进行此优化。毕竟,这是微不足道的。如果您接受const T&and sizeof(T) <= sizeof(void*),则 C++ 引用语义强加的不变量允许编译器简单地替换整个函数体中的值(如果它是胜利的话)。如果不是,那么最坏情况的开销是函数序言中的一个指向参数的取消引用。

于 2012-11-16T01:53:48.873 回答