按值传递参考参数

时间:2016-06-22 12:01:24

标签: c++ c++11 reference pass-by-reference pass-by-value

考虑这个简单的程序:

vector<int> foo = {0, 42, 0, 42, 0, 42};
replace(begin(foo), end(foo), foo.front(), 13);

for(const auto& i : foo) cout << i << '\t';

当我写这篇文章时,我希望得到:

  

13 42 13 42 13 42

但我得到了:

  

13 42 0 42 0 42

问题当然是replace通过引用接收最后2个参数。因此,如果它们中的任何一个碰巧处于正在操作的范围内,结果可能是意外的。我可以通过添加临时变量来解决这个问题:

vector<int> foo = {0, 42, 0, 42, 0, 42};
const auto temp = foo.front();
replace(begin(foo), end(foo), temp, 13);

for(const auto& i : foo) cout << i << '\t';

我知道C ++ 11为我们提供了各种类型的工具,我可以简单地将这个值强制转换为非引用类型并传递内联,而不创建临时的吗?

7 个答案:

答案 0 :(得分:9)

解决方案可以如下(即使你是临时的)

template<class T>
void replace_value_of_first(std::vector<T>& v, const T& value)
{
    std::replace(v.begin(), v.end(), T(v.front()), value);
}

答案 1 :(得分:7)

您可以编写一个引用引用并返回值的简单函数。这将&#34;转换&#34;引用到一个值。这确实会生成一个临时的,但它是未命名的,并将在完整表达式的末尾销毁。像

这样的东西
template<typename T>
T value(const T& ref)
{
    return ref;
}

然后你可以像

一样使用它
int main()                                                   
{                                                            
    vector<int> foo = {0, 42, 0, 42, 0, 42};
    replace(begin(foo), end(foo), value(foo.front()), 13);

    for(const auto& i : foo) cout << i << '\t';                                      
}

输出:

13  42  13  42  13  42

Live Example

答案 2 :(得分:4)

您可以将给定值转换为rvalue以达到预期效果。下面的示例可以在不定义任何额外函数的情况下工作,只需在值中加零即可。

vector<int> foo = {0, 42, 0, 42, 0, 42};
replace(begin(foo), end(foo), foo.front()+0, 13);

for(const auto& i : foo) cout << i << '\t';

甚至(正如Jarod42所建议的)只有一元+运算符,这是一个无操作:

vector<int> foo = {0, 42, 0, 42, 0, 42};
replace(begin(foo), end(foo), +foo.front(), 13);

for(const auto& i : foo) cout << i << '\t';

显然,其中任何一个仍然会造成一个暂时的。我不认为你可以摆脱它。

答案 3 :(得分:1)

特定情况下(当旧值是向量的第一个时),您可以使用<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="node()|@*" name="identity"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="@class"> <xsl:attribute name="class"> <xsl:choose> <xsl:when test=". = 'b1'"> <xsl:text>c1</xsl:text> </xsl:when> <xsl:when test=". = 'b2'"> <xsl:text>c2</xsl:text> </xsl:when> <xsl:otherwise> <xsl:value-of select="." /> </xsl:otherwise> </xsl:choose> </xsl:attribute> </xsl:template> </xsl:stylesheet> rbegin()来反转替换顺序。

一般来说,我不知道是否有可能以简单的方式进行复制。

rend()

p.s:抱歉我的英语不好。

答案 4 :(得分:1)

为了更明确,您可以使用int()作为构造函数来创建临时的:

replace(begin(foo), end(foo), int(foo.front()), 13);

而不是添加值。请参阅Demo

答案 5 :(得分:1)

一个适用于任何类型的衬垫,不仅仅是数字:

replace(begin(foo), end(foo), make_pair(foo.front(),0).first, 13);

或不创建额外字段:

replace(begin(foo), end(foo), get<0>( make_tuple(foo.front()) ), 13);

答案 6 :(得分:1)

vector<int> foo = {0, 42, 0, 42, 0, 42};
replace(begin(foo), end(foo), static_cast<int>(foo.front()), 13);
assert(equal(begin(foo), end(foo), begin({13, 42, 13, 42, 13, 42})));