有什么技巧使用std :: cin初始化一个const变量? [英] Are there any tricks to use std::cin to initialize a const variable?

查看:179
本文介绍了有什么技巧使用std :: cin初始化一个const变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

常见的std :: cin用法

int X;
cin >> X;

这样做的主要缺点是X不能 const 。它可以很容易地引入错误;并且我正在寻找一些技巧,以便能够创建一个const值,并只写一次。

The main disadvantage of this is that X cannot be const. It can easily introduce bugs; and I am looking for some trick to be able to create a const value, and write to it just once.

天真的解决方案 p>

The naive solution

// Naive
int X_temp;
cin >> X_temp;
const int X = X_temp;

您可以通过将X更改为 const& ;仍然,原始变量可以修改。

You could obviously improve it by changing X to const&; still, the original variable can be modified.

我正在寻找一个简单而聪明的解决方案如何做到这一点。我相信我不是唯一一个会从这个问题的好回答中受益的人。

I'm looking for a short and clever solution of how to do this. I am sure I am not the only one who will benefit from a good answer to this question.

//编辑:该解决方案很容易扩展到其他类型(让我们说,所有POD, std :: string 和可移动可复制类与琐碎的构造函数)(如果它不

// I'd like the solution to be easily extensible to the other types (let's say, all PODs, std::string and movable-copyable classes with trivial constructor) (if it doesn't make sense, please let me know in comments).

推荐答案

我可能会选择返回可选,因为流式传输可能失败。要测试它是否(如果你想分配另一个值),使用 get_value_or(默认),如示例所示。

I'd probably opt for returning an optional, since the streaming could fail. To test if it did (in case you want to assign another value), use get_value_or(default), as shown in the example.

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;
}

Live example。

为了进一步确保用户在 T 不是可输入流的,你可以写一个trait类,检查 stream>> T_lvalue 有效, static_assert (如果不是):

To further ensure that the user gets no wall-of-overloads presented when T is not input-streamable, you can write a trait class that checks if stream >> T_lvalue is valid and static_assert if it's not:

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;
}

Live example。

我使用的是 detail :: do_stream s>> x 仍然会在 get_stream 内解析,你仍然会得到我们想要避免的超负荷的墙,当 static_assert 激发。将此操作委托给不同的功能使此工作成功。

I'm using a detail::do_stream function, since otherwise s >> x would still be parsed inside get_stream and you'd still get the wall-of-overloads that we wanted to avoid when the static_assert fires. Delegating this operation to a different function makes this work.

这篇关于有什么技巧使用std :: cin初始化一个const变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆