moooeeeep
moooeeeep

Reputation: 32512

Find out how this variadic templated function works

In this answer I have seen some C++11 code, that I don't really understand (but I would like to).

There, a variadic template function is defined, that (maybe?) takes all arguments passed and inserts them into a std::ostringstream.

This is the function (see the complete working example at the linked answer):

template<typename T, typename... Ts>
std::string CreateString(T const& t, Ts const&... ts)
{
    using expand = char[];

    std::ostringstream oss;
    oss << std::boolalpha << t;
    (void)expand{'\0', (oss << ts, '\0')...};
    return oss.str();
}

When I had to guess, I'd say, a character array is created and initialized with \0-bytes, and the insertion of the function's arguments into the stream happens as a side effect of the initialization (part of that comma expression). In the end, the array contains as many nulls as items were inserted into the stream. It's casted to void in order to avoid a compiler warning (unused variable). Similar to this:

char arr[] = {'\0', (oss << t1, '\0'), (oss << t2, '\0'), ..., (oss << tn, '\0')};

Is my attempt to describe this function's workings accurate? Can someone explain what design decision might be relevant here, and why is it beneficial to implement it this way (the alternative would be compile-time recursion, I guess)?

Upvotes: 2

Views: 86

Answers (1)

moooeeeep
moooeeeep

Reputation: 32512

After receiving some helpful hints in the question's comment section I could figure out some of the points:

  • The feature being used is called pack expansion. It works exactly as described in the OP: a temporary array is initialized with the side effect of stream insertion. A detailed description of the feature can be found here:
  • This is a work-around that is necessary to avoid the recursion approach, which would be less efficient. In C++17 this work-around is no longer needed, because of the then introduced fold expressions:
  • The first array element is initialized \0 to avoid the program being ill-formed if the function was called with only one argument. Else, the array object would be created empty, with an incomplete type (array of unknown bounds), which is illegal. For further reading:

Upvotes: 3

Related Questions