5

I simply would print out a non type template parameter pack. But I can't find a valid expansion if I want to have spaces in between the elements.

Example:


template < int ... N > 
struct X
{
    static void Check() { 
        // this will become std::cout << ( 1 << 2 ) << std::endl; -> prints "4"
        std::cout << "X" << (N << ...) <<  std::endl; 

        // this will become: ((std::cout << 1 ) << 2 ) << std::endl; -> prints "12"
        (std::cout << ... << N) << std::endl;

        // this becomes: (( std::cout << " " << 1 ) << 2 ) -> prints " 12"
        (std::cout << " " << ... << N) << std::endl;

        // the following is not allowed
        (std::cout << ... << " " << N) << std::endl;

        // also this one is not compiling
        (std::cout << ... << N << " ") << std::endl;
    }   
};

int main()
{
    X<1,2>::Check();
}

Is there any chance to expand the parameter pack to print the elements with space in between without using a helper function?

康桓瑋
  • 33,481
  • 5
  • 40
  • 90
Klaus
  • 24,205
  • 7
  • 58
  • 113

2 Answers2

4

With the use of a helper variable.

std::size_t count{};
((std::cout << (count++? " " : "") << N), ...);
bipll
  • 11,747
  • 1
  • 18
  • 32
  • OK, in general the answer is, that we did NOT have a fold expression which can handle it and so we need to expand to a list of separated single couts statements. In the case that the `<<` will not return the input ostream or the ostream will modified with iomanip operators, it will also not work. Thanks! – Klaus Nov 17 '21 at 10:42
  • @Klaus `stream& = std::cout;` ? – Sergey Kolesnik Nov 17 '21 at 12:22
  • @Klaus you can have a temporary string from string stream and than have it outputted with just one ostream – Sergey Kolesnik Nov 17 '21 at 12:25
  • @Klaus this _is_ a fold-expression, with `,` as the operator. In case your stream does not return itself, you can in turn split it further: `((std::cout << (count++? " " : ""), std::cout << N), ...)`. – bipll Nov 17 '21 at 12:55
  • 1
    I prefer branchless version: `const char* sep = ""; (((std::cout << sep << Is), sep = " "), ...);`. – Jarod42 Nov 17 '21 at 13:38
1

Another alternative is to additionally define the first template parameter to facilitate formatting.

#include <iostream>

template<int... N> 
struct X {
  static void Check() { 
    if constexpr (sizeof...(N)) 
      [](auto first, auto... rest) {
        std::cout << first;
        ((std::cout << " " << rest), ...);
        std::cout << "\n";
      }(N...);
  }
};

int main() {
  X<1,2>::Check();
}
康桓瑋
  • 33,481
  • 5
  • 40
  • 90