我可以让C++编译器决定是按值传递还是按引用传递吗?

问题描述 投票:0回答:2

看看这个假设的头文件:

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>
    。无论哪种方式,当实现看起来几乎相同时,这都是大量额外的工作,并且我怀疑编译器在决定是否按值传递方面可以比我做得更好。
  • libc++项目似乎通过内联很多函数来解决这个问题,这样编译器就可以将选择提升一级,但在这种情况下,假设
    ingest
    的实现相当复杂,不值得内联。
    注释中解释了,所有模板函数默认都是
    inline
c++ performance pass-by-value pass-by-const-reference
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:
    ...
};

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


0
投票

虽然提到的 boost 等技巧

call_traits<T>
在这种情况下做了他们声称要做的事情,但我认为你假设编译器在最重要的情况下还没有进行这种优化。 毕竟,这是微不足道的。 如果您接受
const T&
sizeof(T) <= sizeof(void*)
,则 C++ 引用语义强加的不变量允许编译器简单地替换整个函数体中的值(如果它是胜利的话)。如果不是,最坏情况的开销是函数序言中的一个指向参数的指针取消引用。

© www.soinside.com 2019 - 2024. All rights reserved.