首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >怎么写我自己的机械手?

怎么写我自己的机械手?
EN

Stack Overflow用户
提问于 2016-11-27 22:14:51
回答 4查看 1.9K关注 0票数 5

让我们假设我想要为输入和输出编写自己的机械手。

代码语言:javascript
复制
cin >> mymanip >> str;

代码语言:javascript
复制
cout << mymanip << str;

我想要的是我要做的是切换案例,我从输入中读取的字符,并将结果分配给一个字符串。

所以,如果我输入"QwErTy“,就会在字符串中得到"qWeRtY”。

这是一个非常基本的任务,只有一个功能,但我想了解更多关于机械手的知识。

有人能给点线索吗?

谢谢。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2016-11-27 23:14:21

这种方法有点棘手--但可以做到,您可以为流添加自己的机械手。

首先,你需要你的开关:

代码语言:javascript
复制
class toggle_t {};
constexpr toggle_t toggle;

下一步- ostream的版本( istream的情况非常相似.):

在将toggle放到ostream之后-您需要一些特殊的对象:

代码语言:javascript
复制
struct toggled_ostream
{
    std::ostream& os;
};

inline toggled_ostream operator << (std::ostream& os, toggle_t)
{
    return { os };
}

注意,有人可能把toggle放在了错误的位置:cout << toggle << 123 -所以它应该像普通流那样适用于所有其他类型:

代码语言:javascript
复制
template <typename T>
std::ostream& operator << (toggled_ostream tos, const T& v)
{
    return tos.os << v;
}

因此,对于char类型(如charconst char*std::string),编写切换重载。我给您提供了char的版本--为“更长”类型编写版本应该不会有问题:

代码语言:javascript
复制
std::ostream& operator << (toggled_ostream tos, char v)
{
    char c = std::isupper(v) ? std::tolower(v)
                             : std::islower(v) ? std::toupper(v) : v;
    return tos.os << c;
}

工作演示

票数 4
EN

Stack Overflow用户

发布于 2016-11-27 22:25:51

操纵者所做的就是在std::ios_base基类中设置相应的位。

例如,std::setprecision()操作器简单地将基数::精度()放在被操纵的流上。

在gcc的标题中,std::setprecision()的实现几乎是可读的(对于C++库模板实现来说,这是非常罕见的):

代码语言:javascript
复制
 inline _Setprecision  setprecision(int __n)
     { return { __n }; }

std::setprecision()返回一个内部std::_Precision对象。然后,为>> (和类似的<<操作符)为std::_Precision对象提供一个简单的模板重载,处理其余的魔术:

代码语言:javascript
复制
 template<typename _CharT, typename _Traits>
    inline basic_istream<_CharT, _Traits>& 
    operator>>(basic_istream<_CharT, _Traits>& __is, _Setprecision __f)
    { 
      __is.precision(__f._M_n); 
      return __is; 
    }

在您的示例中,std::ios_base类中没有实现所需输入/输出转换的位。因此,操纵者本身不会在这里工作。

你想要做的事情需要一种完全不同、更复杂的方法:

  1. std::[io]stream的一个自定义子类,它使用std::streambuf的自定义子类。
  2. std::streambuf子类从一个链式流中读取或写入,如您所描述的那样转换输入或输出。
  3. 从自定义子类中读取或写入的结果是从链式流中读取或写入数据,从而相应地转换数据。
票数 6
EN

Stack Overflow用户

发布于 2016-11-27 22:27:08

你不能那样做。相反,您可以做的是以字符串为参数的操纵器,即

代码语言:javascript
复制
std::cout << toggle(str);
std::cin  >> toggle(str);

操纵者仅仅是所谓的句法糖,也就是说,它比其他人做事情更方便。例如,

代码语言:javascript
复制
std::cout << std::setw(5) << x <<;

也会像

代码语言:javascript
复制
std::cout.width(5);
std::cout << x;

但是更方便,因为它允许与其他<<操作链接在一起。

现在,您所需要的东西(交换小写字符和大写字符)没有格式化支持,因此也无法为此提供语法糖。

但是,如果机械手可以将您的字符串作为参数,那么当然,您可以实现您想要的,以标准的方式实现机械手。例如,

代码语言:javascript
复制
struct toggle_output
{ std::string const&str; }

inline toggle_output toggle(std::string const&str)
{ return {str}; }

inline std::ostream& operator<<(std::ostream&out, toggle_output const&t)
{
  for(auto c:t.str)
    if     (std::islower(c)) out<<std::toupper(c);
    else if(std::isupper(c)) out<<std::tolower(c);
    else                     out<<c;
  return out;
}

struct toggle_input
{ std::string &str; }

inline toggle_input toggle(std::string&str)
{ return {str}; }

inline std::istream& operator>>(std::istream&in, toggle_input &t)
{
  in >> t.str;
  for(auto&c:t.str)
    if     (std::islower(c)) c=std::toupper(c);
    else if(std::isupper(c)) c=std::tolower(c);
  return in;
}

您还可能需要(以避免混淆)

代码语言:javascript
复制
inline std::ostream& operator<<(std::ostream&out, toggle_input const&t)
{ return out<<toggle_output(t.str); }
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40834544

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档