我试图包装io机械手std::put_money
。这是一个简化的插图:
#include <iomanip>
#include <iostream>
long double scale(long double f) { return f * 100.0L; }
namespace acm {
auto put_money(const long double &f, bool intl = false) {
return std::put_money(scale(f), intl);
}
}
int main() {
long double f(1234.567L);
std::cout << "1: " << acm::put_money(f) << '\n';
std::cout << "2: " << std::put_money(scale(f)) << '\n';
return 0;
}
输出为:
1: -92559631349317829570406876446720000000000000000000000000000000
2: 123457
我研究了MSVC和libc ++的原理,得知std::put_money
返回了一个自定义类型,该类型保留对该值的const引用,而不是进行复制。
第1行可能是错误的,因为流式传输自定义对象时引用无效(即scale
中acm::put_money
返回的临时值已被破坏)。
问:但是,为什么第二行是正确的?
理论1:“运气不好”。保持对临时变量的const引用是一个错误,但是恰好碰巧该值仍然存在于堆栈中,可能是因为该值并未被额外的函数调用所破坏。 (这是因为Release版本通常可以正常工作的事实,大概是因为内联了额外的函数调用。)
理论2:在第二种情况下,通过const引用对临时目录进行终生扩展是有帮助的,但是由于某种原因,它不适用于第一种情况。也许额外的函数调用违反了生命周期延长的规则?
理论3:???
答案 0 :(得分:0)
最终位于标准中指定的位置(为便于阅读,对其进行了略微编辑):
[ext.manip]
template <class moneyT> unspecified put_money(const moneyT& mon, bool intl = false);
Requires:
类型moneyT
可以是long double 或basic_string
模板的特殊化。
Returns:
未指定类型的对象,例如,如果out是类型的对象 basic_ostream然后是表达式out << put_money(mon, intl)
表现为调用的格式化输出函数f(out, mon, intl)
,其中功能f
定义为:[示例省略]
表达式
out << put_money(mon, intl)
的类型应为 basic_ostream&和值out
。
长短之处在于std::put_money
仅在<<
格式的输出运算符的右侧且左侧为std::basic_ostream
的情况下定义。仅您的第2行符合该要求,而第1行则不满足。