How do I concatenate multiple C++ strings on one line?

Viewed 478054

C# has a syntax feature where you can concatenate many data types together on 1 line.

string s = new String();
s += "Hello world, " + myInt + niceToSeeYouString;
s += someChar1 + interestingDecimal + someChar2;

What would be the equivalent in C++? As far as I can see, you'd have to do it all on separate lines as it doesn't support multiple strings/variables with the + operator. This is OK, but doesn't look as neat.

string s;
s += "Hello world, " + "nice to see you, " + "or not.";

The above code produces an error.

24 Answers
#include <sstream>
#include <string>

std::stringstream ss;
ss << "Hello, world, " << myInt << niceToSeeYouString;
std::string s = ss.str();

Take a look at this Guru Of The Week article from Herb Sutter: The String Formatters of Manor Farm

s += "Hello world, " + "nice to see you, " + "or not.";

Those character array literals are not C++ std::strings - you need to convert them:

s += string("Hello world, ") + string("nice to see you, ") + string("or not.");

To convert ints (or any other streamable type) you can use a boost lexical_cast or provide your own function:

template <typename T>
string Str( const T & t ) {
   ostringstream os;
   os << t;
   return os.str();
}

You can now say things like:

string s = string("The meaning is ") + Str( 42 );

Your code can be written as1,

s = "Hello world," "nice to see you," "or not."

...but I doubt that's what you're looking for. In your case, you are probably looking for streams:

std::stringstream ss;
ss << "Hello world, " << 42 << "nice to see you.";
std::string s = ss.str();

1 "can be written as" : This only works for string literals. The concatenation is done by the compiler.

In C++20 you'll be able to do:

auto s = std::format("{}{}{}", "Hello world, ", myInt, niceToSeeYouString);

Until then you could do the same with the {fmt} library:

auto s = fmt::format("{}{}{}", "Hello world, ", myInt, niceToSeeYouString);

Disclaimer: I'm the author of {fmt}.

boost::format

or std::stringstream

std::stringstream msg;
msg << "Hello world, " << myInt  << niceToSeeYouString;
msg.str(); // returns std::string object
auto s = string("one").append("two").append("three")

You would have to define operator+() for every data type you would want to concenate to the string, yet since operator<< is defined for most types, you should use std::stringstream.

Damn, beat by 50 seconds...

Here's the one-liner solution:

#include <iostream>
#include <string>

int main() {
  std::string s = std::string("Hi") + " there" + " friends";
  std::cout << s << std::endl;

  std::string r = std::string("Magic number: ") + std::to_string(13) + "!";
  std::cout << r << std::endl;

  return 0;
}

Although it's a tiny bit ugly, I think it's about as clean as you cat get in C++.

We are casting the first argument to a std::string and then using the (left to right) evaluation order of operator+ to ensure that its left operand is always a std::string. In this manner, we concatenate the std::string on the left with the const char * operand on the right and return another std::string, cascading the effect.

Note: there are a few options for the right operand, including const char *, std::string, and char.

It's up to you to decide whether the magic number is 13 or 6227020800.

Something like this works for me

namespace detail {
    void concat_impl(std::ostream&) { /* do nothing */ }

    template<typename T, typename ...Args>
    void concat_impl(std::ostream& os, const T& t, Args&&... args)
    {
        os << t;
        concat_impl(os, std::forward<Args>(args)...);
    }
} /* namespace detail */

template<typename ...Args>
std::string concat(Args&&... args)
{
    std::ostringstream os;
    detail::concat_impl(os, std::forward<Args>(args)...);
    return os.str();
}
// ...
std::string s{"Hello World, "};
s = concat(s, myInt, niceToSeeYouString, myChar, myFoo);

Based on above solutions I made a class var_string for my project to make life easy. Examples:

var_string x("abc %d %s", 123, "def");
std::string y = (std::string)x;
const char *z = x.c_str();

The class itself:

#include <stdlib.h>
#include <stdarg.h>

class var_string
{
public:
    var_string(const char *cmd, ...)
    {
        va_list args;
        va_start(args, cmd);
        vsnprintf(buffer, sizeof(buffer) - 1, cmd, args);
    }

    ~var_string() {}

    operator std::string()
    {
        return std::string(buffer);
    }

    operator char*()
    {
        return buffer;
    }

    const char *c_str()
    {
        return buffer;
    }

    int system()
    {
        return ::system(buffer);
    }
private:
    char buffer[4096];
};

Still wondering if there will be something better in C++ ?

In c11:

void printMessage(std::string&& message) {
    std::cout << message << std::endl;
    return message;
}

this allow you to create function call like this:

printMessage("message number : " + std::to_string(id));

will print : message number : 10

Stringstream with a simple preproccessor macro using a lambda function seems nice:

#include <sstream>
#define make_string(args) []{std::stringstream ss; ss << args; return ss;}() 

and then

auto str = make_string("hello" << " there" << 10 << '$');

Have you tried to avoid the +=? instead use var = var + ... it worked for me.

#include <iostream.h> // for string

string myName = "";
int _age = 30;
myName = myName + "Vincent" + "Thorpe" + 30 + " " + 2019;
Related