提问人:Jonathan Mee 提问时间:6/22/2016 更新时间:6/22/2016 访问量:602
按值传递给引用参数
Passing to a Reference Argument 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
当然,问题在于它通过引用来获取最后 2 个参数。因此,如果它们中的任何一个恰好在正在操作的范围内,结果可能会出乎意料。我可以通过添加一个临时变量来解决这个问题:replace
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++1 为我们提供了各种类型工具,我是否可以简单地将此值强制为非引用类型并在内联传递该值,而无需创建临时值?
答:
7赞
NathanOliver
6/22/2016
#1
您可以编写一个简单的函数来接受引用并返回一个值。这会将引用“转换”为值。这确实会生成一个临时的,但它是未命名的,将在完整表达式的末尾被销毁。类似的东西
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
9赞
thorsan
6/22/2016
#2
解决方案可以如下所示(即使您正在制作临时解决方案)
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);
}
评论
0赞
Jonathan Mee
6/22/2016
嗯。。。我已经更新了链接的问题来表达问题,但这在 Visual Studio 2015 上不起作用。
0赞
Jonathan Mee
6/23/2016
对于 Visual Studio 用户,可以获得 C++11 合规性,因此无需修改单个项目即可支持此功能:For Visual Studio users you can get 11 compliance so this is supported without modified individual projects: stackoverflow.com/q/37976395/2642059 但是,即使这符合标准,如果没有链接的步骤,Visual Studio 2015 也无法在此处正常运行。
4赞
Smeeheey
6/22/2016
#3
您可以将给定的值转换为 以达到所需的效果。下面的示例无需定义任何额外的函数,只需将零添加到值中即可。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 所建议的)只是一元运算符,这是一个 no-op:+
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';
显然,这些中的任何一个仍然会产生暂时性。我不认为你能摆脱这一点。
评论
0赞
Smeeheey
6/22/2016
是的,那更好。更新的答案
3赞
Jarod42
6/22/2016
甚至.+foo.front()
3赞
Jarod42
6/22/2016
顺便说一句,您的解决方案在一般情况下不适用于任何(至于)。T
std::string
1赞
Jarod42
6/22/2016
@JonathanMee:这是一个无操作,不要更改值(即使为负数)。它相当于他的.+0
1赞
W.F.
6/22/2016
@JonathanMee这实际上等同于手段+0
+int()
1赞
max66
6/22/2016
#4
在这种特殊情况下(当旧值是向量的第一个值时),可以用 和 反转替换顺序。rbegin()
rend()
总的来说,我不知道是否有可能,以一种简单的方式,不制作副本。
int main ()
{
std::vector<int> foo = {0, 42, 0, 42, 0, 42};
std::replace(foo.rbegin(), foo.rend(), foo.front(), 13);
for(const auto & i : foo)
std::cout << i << '\t';
std::cout << std::endl;
return 0;
}
p.s.:对不起,我的英语不好。
1赞
kwarnke
6/22/2016
#5
更明确地说,您可以用作构造函数来创建临时的:int()
replace(begin(foo), end(foo), int(foo.front()), 13);
而不是添加值。请参阅演示。
评论
1赞
Slava
6/22/2016
#6
一个应该适用于任何类型的衬里,而不仅仅是数字:
replace(begin(foo), end(foo), make_pair(foo.front(),0).first, 13);
或者不创建额外的字段:
replace(begin(foo), end(foo), get<0>( make_tuple(foo.front()) ), 13);
1赞
Glenn Downing
6/22/2016
#7
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})));
评论
0赞
Jonathan Mee
6/22/2016
哈哈:stackoverflow.com/questions/37969114/...事实证明,它在Visual Studio 2015上不起作用。
下一个:按值或引用传递容器
评论
replace(begin(foo), end(foo), int(foo.front()), 13);