Bar*_*icz 43 c++ iostream c++11
常见的std :: cin用法
int X;
cin >> X;
Run Code Online (Sandbox Code Playgroud)
这样做的主要缺点是X不能const.它很容易引入错误; 我正在寻找一些技巧来创建一个const值,并只写一次.
天真的解决方案
// Naive
int X_temp;
cin >> X_temp;
const int X = X_temp;
Run Code Online (Sandbox Code Playgroud)
你可以通过改变X来明显改善它const&; 仍然可以修改原始变量.
我正在寻找一个如何做到这一点的简短而聪明的解决方案.我相信我不是唯一一个能从这个问题的答案中获益的人.
//编辑:我希望解决方案可以轻松扩展到其他类型(比方说,所有POD,std::string以及带有普通构造函数的可移动可复制类)(如果没有意义,请在评论中告诉我) .
Xeo*_*Xeo 22
我可能会选择返回optional,因为流媒体可能会失败.要测试它是否(如果您想要分配另一个值),请使用get_value_or(default),如示例中所示.
template<class T, class Stream>
boost::optional<T> stream_get(Stream& s){
T x;
if(s >> x)
return std::move(x); // automatic move doesn't happen since
// return type is different from T
return boost::none;
}
Run Code Online (Sandbox Code Playgroud)
为了进一步确保用户在没有T输入流传输时不会出现重载墙,您可以编写一个特征类来检查是否stream >> T_lvalue有效以及static_assert是否有效:
namespace detail{
template<class T, class Stream>
struct is_input_streamable_test{
template<class U>
static auto f(U* u, Stream* s = 0) -> decltype((*s >> *u), int());
template<class>
static void f(...);
static constexpr bool value = !std::is_void<decltype(f<T>(0))>::value;
};
template<class T, class Stream>
struct is_input_streamable
: std::integral_constant<bool, is_input_streamable_test<T, Stream>::value>
{
};
template<class T, class Stream>
bool do_stream(T& v, Stream& s){ return s >> v; }
} // detail::
template<class T, class Stream>
boost::optional<T> stream_get(Stream& s){
using iis = detail::is_input_streamable<T, Stream>;
static_assert(iis::value, "T must support 'stream >> value_of_T'");
T x;
if(detail::do_stream(x, s))
return std::move(x); // automatic move doesn't happen since
// return type is different from T
return boost::none;
}
Run Code Online (Sandbox Code Playgroud)
我正在使用一个detail::do_stream函数,因为否则s >> x仍会在内部解析get_stream,你仍然会得到我们想要在static_assert火灾时避免的重载墙.将此操作委派给不同的功能可以使这项工作成功.
lx.*_*lx. 18
你可以在这种情况下使用lambdas:
const int x = []() -> int {
int t;
std::cin >> t;
return t;
}();
Run Code Online (Sandbox Code Playgroud)
(注意末尾的额外()).
这不是编写单独的函数,而是在读取代码时不必在源文件中跳转.
编辑:因为在评论中声明这违反了DRY规则,您可以利用auto并5.1.2:4减少类型重复:
5.1.2:4 状态:
[...]如果lambda表达式不包含trailing-return-type,则就好像trailing-return-type表示以下类型:
如果复合语句是形式
{ attribute-specifier-seq(opt) return expression ; }lvalue-to-rvalue转换(4.1),数组到指针转换(4.2)和函数到指针转换(4.3)之后返回表达式的类型;
否则,无效.
所以我们可以改变代码看起来像这样:
const auto x = [] {
int t;
std::cin >> t;
return t;
}();
Run Code Online (Sandbox Code Playgroud)
我无法决定这是否更好,因为该类型现在已经"隐藏"在lambda体内...
编辑2:在评论中指出,只是删除可能的类型名称,不会导致"干燥正确"的代码.此外,在这种情况下,尾随返回类型推导实际上是MSVC++以及g ++和(尚未)标准的扩展.
eca*_*mur 12
略微调整lx.的lambda解决方案:
const int x = [](int t){ return iss >> t, t; }({});
Run Code Online (Sandbox Code Playgroud)
显着减少DRY违规; 可以通过const int x改为const auto x:
const auto x = [](int t){ return iss >> t, t; }({});
Run Code Online (Sandbox Code Playgroud)
进一步改进; 你可以将副本转换为移动,否则逗号运算符会在12.8:31中抑制优化(移动构造函数被逗号运算符抑制):
const auto x = [](int t){ return iss >> t, std::move(t); }({});
Run Code Online (Sandbox Code Playgroud)
请注意,这仍然可能比lx.的lambda效率低,因为它可以从NRVO中受益,而这仍然必须使用移动构造函数.另一方面,优化编译器应该能够优化非副作用的移动.
您可以调用函数来返回结果并在同一语句中初始化:
template<typename T>
const T in_get (istream &in = std::cin) {
T x;
if (!(in >> x)) throw "Invalid input";
return x;
}
const int X = in_get<int>();
const string str = in_get<string>();
fstream fin("myinput.in",fstream::in);
const int Y = in_get<int>(fin);
Run Code Online (Sandbox Code Playgroud)
如果您有C++ 11,那么如果您使用auto&&关键字,则只能指定一次类型.
auto&& X = in_get<int>();
Run Code Online (Sandbox Code Playgroud)
当然你可以做到这一点,只是构建一个临时的istream_iterator. 例如:
const auto X = *istream_iterator<int>(cin)
Run Code Online (Sandbox Code Playgroud)
值得在这里指出的是,当您这样做时,您将放弃所有错误检查的希望。通常从用户那里获取输入不会被认为是最明智的......但是,嘿,也许你以某种方式策划了这个输入?
| 归档时间: |
|
| 查看次数: |
11346 次 |
| 最近记录: |