使用<<函数内部的运算符

时间:2015-03-15 13:26:04

标签: c++ arguments stringstream

我想创建一个允许我在参数中使用<<运算符的函数,并在其中使用相应的字符串流。

类似的东西:

/* This does not do what i want below */
void printStream(std::stringstream& ss) {
  std::cout << ss.str();
}

/* Desired function usage */
printStream("The number is: " << 42 << ".");

我应该在函数声明中使用什么?

修改

根据Deduplicator建议,我尝试使用可变参数模板。出于我的目的,我决定创建一个模板,该模板获取参数列表并返回组合字符串。

这是代码:

template <typename First, typename... Rest> void getStringInner(std::stringstream& ss, const First& first, const Rest&... rest) {
  ss << first;
  getStringInner(ss, rest...);
}

template <typename First, typename... Rest> std::string getString(const First& first, const Rest&... rest) {
  std::stringstream ss;
  getStringInner(ss, first, rest...);
  return ss.str();
}

不幸的是,Visual Studio给了我一个错误:

  

错误C2678:二进制&#39;&lt;&lt;&# :没有找到左手的操作员   类型&#39; std :: stringstream&#39;的操作数(或者没有可接受的   转换)main.cpp 42测试

ss << first;中有错误的行为getStringInner

我做错了什么?

EDIT2:

我发现了错误。这是工作代码:

template <typename First> void getStringInner(std::stringstream& ss) {}

template <typename First> void getStringInner(std::stringstream& ss, const First& first) {
  ss << first;
}

template <typename First, typename... Rest> void getStringInner(std::stringstream& ss, const First& first, const Rest&... rest) {
  ss << first;
  getStringInner(ss, rest...);
}

template <typename First, typename... Rest> std::string getString(const First& first, const Rest&... rest) {
  std::stringstream ss;
  getStringInner(ss, first, rest...);
  return ss.str();
}

5 个答案:

答案 0 :(得分:2)

不要这样做,它需要一个预处理程序 - 黑客。

只需使用可变参数模板和逗号代替左移:

template<class... X> void printStream(X&&... x) {
    std::stringstream ss;
    ((void)0, (void)(ss<<x), ...);
    std::cout << ss.rdbuf();
}

答案 1 :(得分:1)

您在C ++中寻找的内容很难,因为传递给函数的表达式将独立计算;例如,如果ab是整数,则无法编写函数或模板foo以便

 foo(a << b);

做一些不同于调用foo传递a移位b(编译器将单独查看a << b,从而生成一个bithift操作。)

你可以做的是使用预处理器,即通过编写预处理器宏,foo可以生成你正在寻找的东西。

#define foo(x)                \
   do{                        \
       std::ostream s_;       \
       s_ << x;               \
       std::cout << s_.str(); \
   } while(0)

这项工作通过利用通常被认为是C预处理器的限制,即它通过文本替换来工作。换句话说,编译器将被要求编译s_ << a << b

答案 2 :(得分:1)

您可以使用宏:

#define printStream(arg) std::cout << arg

因此,当您编写printStream("The number is: " << 42 << ".");时,它将扩展为:

std::cout << "The number is: " << 42 << ".";

你想做什么。

答案 3 :(得分:0)

如果不更改通话网站,您将无法执行此操作。 "The number is: " << 42只是一个带有char[]int操作数的移位操作,不管表达式的结果是否应该传递给其他函数。

如果您愿意稍微更改调用,则可以使用重载operator<<的代理类,并将工作委派给std::ostringstream。这是一个基本的例子:

#include <iostream>
#include <sstream>
#include <string>

class Printer {
private:
  std::ostringstream oss;

public:

  Printer() {
  }

  std::string string() const {
      return oss.str();
  }

  template <class T>
  Printer& operator<<(T const& t) {
    oss << t;
    return *this;
  }
};

void printStream(Printer const& printer) {
  std::cout << printer.string();
}


int main() {
  printStream(Printer() << "The number is: " << 42 << ".");
}

答案 4 :(得分:0)

我想到的是创建自己的字符串类,例如Cl_CharArray,并添加运算符&lt;&lt;这将从左右两个字符串中生成一个新的Cl_CharArray

可能需要使用模板。这个任务很有趣,我也会在某个时候做,然后回到这里。然后每个类都需要一个函数来使它成为一个字符串(char数组)。我认为至少有一方(任何一个操作员的左侧或右侧)必须是一个类,所以它应该没问题(有一个数字)。