Search code examples
c++c++11sequencevariadic-templatesvariadic

Printing compile-time integer sequence in C++11


So I'm doing a bit of homework where I have to write my own compile-time integer sequence in C++11 and write a few functions for it (print, concat, sort etc.) but I'm having a bit of trouble wrapping my head around how I would go about writing these things.

template<typename T, typename Comp = std::less<int>>
struct Facility{

    template<T ... Nums>
    struct List{

        struct Element<T ... nums>{};

        template<unsigned num, T val, T ... rest>
        struct Element{
            unsigned index = num;
            T value = val;
            Element<index-1, rest...> others;
        };

        template<unsigned num, T val, T ... rest>
        struct Element<0, val>{
            unsigned index = 0;
            T value = val;
        };

        static constexpr Element<sizeof...(Nums)-1,Nums...> elem = {};

        static void Print()
        {
            // Prints out the list
        }
    };

};

using IntList = typename Facility<int>::List<intlist...>;

int main()
{
    using List1 = IntList<1, 2, 3>;
    List1::print()
}

I'd just like to know if I'm on the right track so I don't work myself into a dead end. I'm not 100% sure on the static print() and the static constexpr member in List, though I can't think of any other way to make it work.


Solution

  • Isn't clear to me what exactly do you want obtain and the meaning of what you have done (why Facility? why List inside facility?).

    I just give you an example of how to write Print() without recursion, using an unused array (and defining IntList, as suggested by Yakk, taking inspiration from std::integer_sequence)

    #include <iostream>
    #include <functional>
    
    template <typename T, T ... Nums>
    struct IntList
     {
       static void Print (std::ostream & s = std::cout)
        {
          using unused = int[];
          (void)unused { 0, ((void)(s << Nums << ", "), 0)... };
          s << std::endl;
        }
     };
    
    int main()
     {
       using List1 = IntList<int, 1, 2, 3>;
       List1::Print();
     }
    

    If you can use C++17 instead of C++11/C++14, you can write Print() without the unused hack, simply unpacking Nums as follows

       static void Print (std::ostream & s = std::cout)
        { (s << ... << (s << Nums, ", ")) << std::endl; }
    

    Regarding concat and sort, I suppose you want member function that return (by example, the concat) a IntList with a concatenation of the two lists of numbers.

    The a simple concat example can be the following static member for IntList

    template <T ... Nums2>
    static constexpr IntList<T, Nums..., Nums2...>
       Concat (IntList<T, Nums2...> const &)
     { return {}; } 
    

    So you can write something like

    constexpr IntList<int, 1, 2, 3> l1;
    constexpr IntList<int, 4, 5, 6> l2;
    
    constexpr auto l3 = l1.Concat(l2);
    
    l3.Print(); // print 1, 2, 3, 4, 5, 6,
    

    I leave you the sort function as simple exercise :-)