put_money是否按值或引用保存其参数
Does put_money hold its argument by value or reference?
以下行为是否调用未定义的行为?
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <experimental/iterator>
int main() {
long double values[] = {1, 2, 3};
std::transform(
std::begin(values), std::end(values),
std::experimental::make_ostream_joiner(std::cout, ", "),
[](long double v) {
return std::put_money(v + 1);
}
);
return 0;
}
我担心的是return std::put_money(v + 1)
返回对临时v + 1
的引用。
标准 ([ext.manip]/6( 仅定义了以下特定表达式:
out << put_money(mon, intl);
目前还未指定mon
如何同时存储,并且绝对有可能成为悬而未决的引用并成为UB。
一个"简单"的解决方法是创建自己的类来知道您存储值:
struct money_putter {
long double value;
template<class charT, class traits>
friend std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os, const money_putter& mon) {
return os << std::put_money(mon.value);
}
};
int main() {
int values[] = {1, 2, 3};
std::transform(
std::begin(values), std::end(values),
std::experimental::make_ostream_joiner(std::cout, ", "),
[](int i) {
return money_putter{i}; // or i + 1
}
);
return 0;
}
您可以对其进行测试,尽管这不会告诉您有关它是否得到保证的任何信息,但是由于未指定put_money的返回类型,因此不能假设返回值不包含引用。
。无论如何,让我们测试一下:
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <experimental/iterator>
int main() {
int i = 42;
std::cout << std::put_money(i) << "n";
auto x = std::put_money(i);
i = 43;
std::cout << x;
return 0;
}
叮当声输出:
42
43
所以实际上答案是肯定的。使用 clang 时,返回的值确实包含引用,并且输出与 gcc 相同。因此,是的,您的代码具有 UB。
这个答案在回答我的问题方面做得很好,但我想我会提供一个更通用的解决方案来确保输出到ostream_joiner
的对象不带悬而未决的引用,一个使用 lambda 来捕获这些引用的问题:
#include <type_traits>
#include <ostream>
template<typename F>
class put_invocation_t {
public:
constexpr put_invocation_t(F const& f) : f(f) {}
constexpr put_invocation_t(F&& f) : f(std::move(f)) {}
template<class charT, class traits>
friend std::basic_ostream<charT, traits>& operator<<(
std::basic_ostream<charT, traits>& os, put_invocation_t const& pi
) {
return pi.f(os);
}
private:
F f;
};
// or use a deduction guide in C++17
template<typename F>
put_invocation_t<std::decay_t<F>> put_invocation(F&& f) {
return put_invocation_t<std::decay_t<F>>(std::forward<F>(f));
}
用作
std::transform(
std::begin(values), std::end(values),
std::experimental::make_ostream_joiner(std::cout, ", "),
[](long double v) {
return put_invocation([=](auto& os) -> auto& {
return os << std::put_money(v + 1);
});
}
);
这样做的好处是还可以通过在transform
中使用类似以下内容的内容来缩放到输出多个值:
return put_invocation([=](auto& os) -> auto& {
return os << "Value is: " << std::put_money(v + 1);
});
相关文章:
- 在全局变量中保存类的实例以重新创建类(创建"backup")
- 将对象数组的引用传递给函数
- 如何在选项卡视图Qt中设置一个新项目,并保存以前的项目
- 什么时候在C++中返回常量引用是个好主意
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 何时在引用或唯一指针上使用移动语义
- 如何在C++中使用 void* 在指针作为对方法的引用传递时保存uint32_t的值
- C++ 类型转换基础 PTR 到派生 PTR 保存在引用类中
- 在循环迭代期间将引用保存到矢量中的空指针
- 如何保存指向抽象基类的指针/引用,但在 c++ 中仍然可以复制
- 多个实例保存对unique_ptr的引用
- put_money是否按值或引用保存其参数
- 对"保存::速率"的未定义引用
- 使元组保存常量引用或常量值
- 为什么引用对象仅保存特定类型的引用
- 如何使用weak_ptr构造一个对象,该对象保存对父项的引用
- 如何获取boost::any保存的数据的const引用
- 如何从c++返回对动态类型的引用并在Python中保存它?
- 未保存创建的对象。按引用传递
- 指针和引用如何保存在内存中