6

I am using a fold expression to print elements in a variadic pack, but how do I get a space in between each element?

Currently the output is "1 234", the desired output is "1 2 3 4"

template<typename T, typename Comp = std::less<T> >
struct Facility
{
template<T ... list>
struct List
{
    static void print()
    {

    }
};
template<T head,T ... list>
struct List<head,list...>
{
    static void print()
    {
     std::cout<<"\""<<head<<" ";
     (std::cout<<...<<list);
    }
};
};

template<int ... intlist>
using IntList = typename Facility<int>::List<intlist...>;
int main()
{
 using List1 = IntList<1,2,3,4>;
 List1::print();
}
Rakete1111
  • 47,013
  • 16
  • 123
  • 162
Lim Ta Sheng
  • 371
  • 3
  • 8

5 Answers5

10

If you need space only between numbers (and not after the last or before the first too), you might do:

template <std::size_t... Is>
void print_seq(std::index_sequence<Is...>)
{
    const char* sep = "";
    (((std::cout << sep << Is), sep = " "), ...);
}

Demo

(It is similar to my "runtime version") for regular containers with for-loop.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
9

you can that

#include <iostream>

template<typename T>
struct Facility
{
template<T head,T ... list>
struct List
{
    static void print()
    {
     std::cout<<"\"" << head;
     ((std::cout << " " << list), ...);
      std::cout<<"\"";
    }
};
};

template<int ... intlist>
using IntList = typename Facility<int>::List<intlist...>;
int main()
{
 using List1 = IntList<1,2,3,4>;
 List1::print();
}

the fold expression ((std::cout << " " << list), ...) will expands to ((std::cout << " " << list1), (std::cout << " " << list2), (std::cout << " " << list3)...)

Tyker
  • 2,971
  • 9
  • 21
7

In general, you use recursion for tasks like this.

You have to define what happens when there are 2 or more and 1 elements in the list and recursively fall back to those definitions:

template <int ...> struct List;
template <int First, int Second, int ... More> struct List {
    static void print() {
        std::cout << First << " ";
        List<Second, More ...>::print();
    }
};
template <int Last> struct List {
    static void print() {
        std::cout << Last;
    }
};
Markus Mayr
  • 4,038
  • 1
  • 20
  • 42
  • but if my packs have thousand of elements that recursion would fail. – Lim Ta Sheng Jul 11 '18 at 09:38
  • 4
    Packs might not be the best choice for having thousands of elements, though – deW1 Jul 11 '18 at 09:41
  • Recursion does `O(N)` instantiations, whereas folding expression allows `O(1)` instantiation (which shouldn't change runtime execution, but compilation time). – Jarod42 Apr 10 '19 at 08:52
1

You can reuse print() to achieve this behaviour. Afterall you are doing a fold operation which is by definition resursive.

Live Demo

template<T head,T ... rest_of_pack>

struct List<head , rest_of_pack...>
{
    static void print_()
    {
     std::cout<<head<<" ";
     List<rest_of_pack...>::print();

    }
};

If you want to process many elements this way you might run into problems with template depth (gcc for instance has a limit of 900). Lucky for you you can use the -ftemplate-depth= option to tweak this behaviour.

You can compile with -ftemplate-depth=100000 and make it work. Note that compilation time will skyrocket (most likely) or in thhe worst case you run out of memory.

Davide Spataro
  • 7,319
  • 1
  • 24
  • 36
0

Not perfectly aligned with the question but I think may be useful putting here a solution based on fold expressions that generates a string from string-like arguments that should minimize dynamic memory allocations:

#include <iostream>
#include <concepts> // std::convertible_to
#include <string>
#include <string_view>
using namespace std::literals;

template<std::convertible_to<std::string_view>... Args>
[[nodiscard]] std::string mystrconcat(Args&&... args)
{
    std::string s;
    const std::size_t totsiz = sizeof...(args) + (std::size(args) + ...);
    s.reserve(totsiz);
    ((s+=args, s+=' '), ...);
    if(!s.empty()) s.resize(s.size()-1); // Get rid of the trailing delimiter?
    return s;
}

int main()
{
    std::cout << '\"' << mystrconcat("aa"s,"bb"sv,"ccc") << '\"' << '\n';
}
MatG
  • 574
  • 2
  • 7
  • 19