Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to construct a std::string with embedded values, i.e. "string interpolation"?

I want to create a string with embedded information. One way (not the only way) of achieving what I want is called string interpolation or variable substitution, wherein placeholders in a string are replaced with actual values.

In C, I would do something like this:

printf("error! value was %d but I expected %d",actualValue,expectedValue) 

whereas if I were programming in python, I would do something like this:

"error! value was {0} but I expected {1}".format(actualValue,expectedValue) 

both of these are examples of string interpolation.

How can I do this in C++?

Important Caveats:

  1. I know that I can use std::cout if I want to print such a message to standard output (not string interpolation, but prints out the kind of string I want):
cout << "error! value was " << actualValue << " but I expected " << expectedValue; 

I don't want to print a string to stdout. I want to pass a std::string as an argument to a function (e.g. the constructor of an exception object).

  1. I am using C++11, but portability is potentially an issue, so knowing which methods work and don't work in which versions of C++ would be a plus.

Edit

  1. For my immediate usage, I'm not concerned about performance (I'm raising an exception for cryin' out loud!). However, knowing the relative performance of the various methods would be very very useful in general.

  2. Why not just use printf itself (C++ is a superset of C after all...)? This answer discusses some reasons why not. As far as I can understand, type safety is a big reason: if you put %d, the variable you put in there had better really be convertible to an integer, as that's how the function figures out what type it is. It would be much safer to have a method which uses compile-time knowledge of the actual type of the variables to be inserted.

like image 389
stochastic Avatar asked Jun 21 '16 23:06

stochastic


People also ask

How do you add in string interpolation?

Structure of an interpolated string. To identify a string literal as an interpolated string, prepend it with the $ symbol. You can't have any white space between the $ and the " that starts a string literal. To concatenate multiple interpolated strings, add the $ special character to each string literal.

Is there string interpolation in C++?

Interpolated literals provide a terse and readable syntax to generate strings embedding results of C++ expressions in a human-readable manner.

How is string interpolation performed?

String interpolation is a process of injecting value into a placeholder (a placeholder is nothing but a variable to which you can assign data/value later) in a string literal. It helps in dynamically formatting the output in a fancier way. Python supports multiple ways to format string literals.

What is string interpolation syntax?

In computer programming, string interpolation (or variable interpolation, variable substitution, or variable expansion) is the process of evaluating a string literal containing one or more placeholders, yielding a result in which the placeholders are replaced with their corresponding values.


2 Answers

In C++20 you will be able to use std::format.

This will support python style formatting:

string s = std::format("{1} to {0}", "a", "b"); 

There is already an implementation available: https://github.com/fmtlib/fmt.

like image 70
Stephan Dollberg Avatar answered Sep 25 '22 18:09

Stephan Dollberg


Method 1: Using a string stream

It looks like std::stringstream gives a quick solution:

std::stringstream ss; ss << "error! value was " << actualValue << " but I expected " <<  expectedValue << endl;  //example usage throw MyException(ss.str()) 

Positive

  • no external dependencies
  • I believe this works in C++ 03 as well as c++ 11.

Negative

  • reportedly quite slow
  • a bit more messy: you must create a stream, write to it, and then get the string out of it.

Method 2: Boost Format

The Boost Format library is also a possibility. Using this, you would do:

throw MyException(boost::format("error! value was %1% but I expected %2%") % actualValue % expectedValue); 

Positive

  • pretty clean compared to stringstream method: one compact construct

Negative

  • reportedly quite slow: uses the stream method internally
  • it's an external dependency

Edit:

Method 3: variadic template parameters

It seems that a type-safe version of printf can be created by using variadic template parameters (the techincal term for a template that takes an indefinite number of template parameters). I have seen a number of possibilities in this vein:

  • This question gives a compact example and discusses performance problems with that example.
  • This answer to that question, whose implementation is also quite compact, but reportedly still suffers from performance issues.
  • The fmt library, discussed in this answer, is reportedly quite fast and seems to be as clean as printf itself, but is an external dependency

Positive

  • usage is clean: just call a printf-like function
  • The fmt library is reportedly quite fast
  • The other options seem quite compact (no external dependency required)

Negative

  • the fmt library, while fast, is an external dependency
  • the other options apparently have some performance issues
like image 26
stochastic Avatar answered Sep 22 '22 18:09

stochastic