Reputation: 12415
I want to create a function that allows me to use the <<
operator in argument and inside it uses the corresponding stringstream.
Something like:
/* 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 << ".");
What should I use in function declaration?
EDIT:
Following Deduplicator suggestion, I'm trying to use variadic template. For my purposes, I've decided to create a template that takes a list of argument and returns the composed string.
This is the code:
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();
}
Unfortunately Visual Studio gives me an error:
error C2678: binary '<<' : no operator found which takes a left-hand operand of type 'std::stringstream' (or there is no acceptable conversion) main.cpp 42 Test
The row with error is ss << first;
in getStringInner
.
What I'm doing wrong?
EDIT2:
I've found the error. This is the working code:
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();
}
Upvotes: 3
Views: 187
Reputation: 42828
You could use a macro:
#define printStream(arg) std::cout << arg
Thus when you write printStream("The number is: " << 42 << ".");
it will expand to:
std::cout << "The number is: " << 42 << ".";
Which does what you wanted.
Upvotes: 1
Reputation: 72
what comes to my mind is creating your own string class, example Cl_CharArray
, and to it add operator<< which would make a new Cl_CharArray
from the strings left and right.
maybe using template will be needed. this task is fun, I will also do it sometime and return here. each class would then need a function to make it into a string (char array). I think at least one side (left or right from any operator) has to be a class, so it should be okay (that there is a number).
Upvotes: 0
Reputation: 27518
You will not be able to do this without changing the call site. "The number is: " << 42
is just a shift operation with a char[]
and an int
operand, regardless of the fact that the result of the expression is then supposed to be passed to some other function.
If you are willing to slightly change the calls, then you can use a proxy class that overloads operator<<
and delegates the work to an std::ostringstream
. Here is a basic example:
#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 << ".");
}
Upvotes: 0
Reputation: 45654
Don't do that, it needs a preprocessor-hack.
Just use a variadic template and comma instead of left-shift:
template<class... X> void printStream(X&&... x) {
std::stringstream ss;
((void)0, (void)(ss<<x), ...);
std::cout << ss.rdbuf();
}
Upvotes: 2
Reputation: 114461
What you're looking for is difficult in C++ because the expression passed to a function will be computed independently; for example if a
and b
are integers there is no way to write a function or template foo
so that
foo(a << b);
does something different from calling foo
passing a
shifted by b
(the compiler will look at a << b
in isolation thus generating a bitshift operation).
What you can do is using the preprosessor, i.e. it's possible to have foo
generating what you're looking for by writing a preprocessor macro.
#define foo(x) \
do{ \
std::ostream s_; \
s_ << x; \
std::cout << s_.str(); \
} while(0)
this work by leveraging what is normally considered a limitation of the C preprocessor, i.e. that it works by textual substitution. The compiler in other words will be asked to compile s_ << a << b
.
Upvotes: 1