What does this trick do? using unpack = int[]...


1
2
3
4
5
6
7
8
  template<typename... T>
  std::string get_error_message(T&&... args) {
       std::ostringstream stream;
       using unpack = int[];
       static_cast<void>(unpack{0, (static_cast<void>(static_cast<void>(stream << args)), 0)...});
       //stream << sqlite3_errmsg(db);
       return stream.str();
   }


why so many static_cast<void>???

is there a simpler way to accomplish the same thing?


I can do this and works fine... unpack = int[] (what does no extent mean?)


 
unpack{ 0, ((stream << args), 0)... };


The result is:


{0,0,0,0} if sizeof...args == 3


Why using unpack??

This is an obsolete (C++11/14) hack used to ensure that the expression (stream << args) is evaluated for each argument in the parameter pack in left-to-right order. For example, if args is a pack of 3 ints with values 1, 2, 3
Then this will evaluate
1
2
3
(stream << 1)
(stream << 2)
(stream << 3)
In order. The obvious ways of attempting this don't/didn't work for a variety of subtle reasons.

The innermost static_cast<void> is required to make sure the code calls the built-in comma;
The middle static_cast<void> is required to silence a compiler warning about the left operand of the comma being discarded;
The outermost static_cast<void> is required to silence a compiler warning about a discarded value expression.

The type alias for unpack is required to satisfy the language grammar.

In C++11/14 this hack was an alternative to a recursive function template.

Since C++17, it can be replaced with a fold expression as follows:
((void)(stream << args), ...);
In this case, the cast ensures that the fold expression uses the built-in comma.
Last edited on
Thanks!!


Topic archived. No new replies allowed.