按值传递给参考参数
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
问题当然是 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 为我们提供了各种类型工具,我是否可以简单地将此值强制为非引用类型并传递内联,而不创建临时类型?
您可以编写一个接受引用和 returns 值的简单函数。这会将 "convert" 引用转换为一个值。这确实会生成一个临时文件,但它是未命名的,并且会在完整表达式的末尾被销毁。像
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
一个解决方案可能如下(即使你是临时的)
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);
}
您可以将给定值转换为 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';
显然,其中任何一个仍然会创建一个临时文件。我不认为你可以摆脱它。
在这个特殊情况下(当旧值是向量的第一个时),你可以用rbegin()
和[=12=颠倒替换顺序].
总的来说,我不知道是否有可能,以一种简单的方式,无需复制。
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.: 抱歉我的英语不好
更明确地说,您可以使用 int()
作为构造函数来创建临时对象:
replace(begin(foo), end(foo), int(foo.front()), 13);
而不是添加一个值。参见 Demo。
一种适用于任何类型的衬垫,而不仅仅是数字:
replace(begin(foo), end(foo), make_pair(foo.front(),0).first, 13);
或不创建额外字段:
replace(begin(foo), end(foo), get<0>( make_tuple(foo.front()) ), 13);
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})));
考虑这个简单的程序:
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 为我们提供了各种类型工具,我是否可以简单地将此值强制为非引用类型并传递内联,而不创建临时类型?
您可以编写一个接受引用和 returns 值的简单函数。这会将 "convert" 引用转换为一个值。这确实会生成一个临时文件,但它是未命名的,并且会在完整表达式的末尾被销毁。像
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
一个解决方案可能如下(即使你是临时的)
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);
}
您可以将给定值转换为 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';
显然,其中任何一个仍然会创建一个临时文件。我不认为你可以摆脱它。
在这个特殊情况下(当旧值是向量的第一个时),你可以用rbegin()
和[=12=颠倒替换顺序].
总的来说,我不知道是否有可能,以一种简单的方式,无需复制。
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.: 抱歉我的英语不好
更明确地说,您可以使用 int()
作为构造函数来创建临时对象:
replace(begin(foo), end(foo), int(foo.front()), 13);
而不是添加一个值。参见 Demo。
一种适用于任何类型的衬垫,而不仅仅是数字:
replace(begin(foo), end(foo), make_pair(foo.front(),0).first, 13);
或不创建额外字段:
replace(begin(foo), end(foo), get<0>( make_tuple(foo.front()) ), 13);
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})));