fbi open_up
fbi open_up

Reputation: 101

How can I template my print function on std::ostream?

So far, I have a function print:

template < char Sep = ' ', class... Args >
void print(Args&&... args)
{
    ([](Args&& arg)
        {
            std::cout << arg << Sep;
        }(std::forward<Args>(args)), ...);

    std::cout << '\n';
}

int main()
{
    print("a", 'b', 3, 4.0, 5.0f, true);
}

I want to template it on std::ostream so that I can print to the buffer I want but I am struglling. Here is what I tried (I have put errors as comment in the code):

//Error: a nontype parameter may not have class type
template < std::ostream os, char Sep = ' ', class... Args >
void print(Args&&... args){ /*omitted code */ os << arg << Sep; }

int main()
{
    print("a", 'b', 3, 4.0, 5.0f, true);
}

I though maybe I could use a class to work-around the problem:

template < class Buffer >
class Printer
{
public:
    void Set(Buffer* buff)
    {
        this->buff = buff;
    }

    //Error: the usage of 'Printer<std::ostream>::buff' requires the compiler
    //to capture this but the current default capture mode does not allow it
    template < char Sep = ' ', class... Args >
    void operator()(Args&&... args)
    {
        ([](Args&& arg)
            {
                (*buff) << arg << Sep;
            }(std::forward<Args>(args)), ...);

        std::cout << '\n';
    }

private:
    Buffer* buff;
};

int main()
{
    Printer<std::ostream> print;
    print.Set(&std::cout);
    print("a", 'b', 3, 4.0, 5.0f, true);
}

Upvotes: 0

Views: 171

Answers (1)

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 123084

Use an ordinary template argument and pass the stream as parameter to the function:

#include <iostream>


template <typename stream, char Sep = ' ', class... Args >
void print(stream& out,Args&&... args)
{
    ([&out](Args&& arg)
        {
            out << arg << Sep;
        }(std::forward<Args>(args)), ...);

    std::cout << '\n';
}

int main()
{
    print(std::cout,"a", 'b', 3, 4.0, 5.0f, true);
}

If only std::ostreams are ok you need not make it a template, but simply use an std::ostream& argument. The standard library makes use of inheritance only sparingly, but for streams there are base classes that can be used when you want to use standard streams.


PS: As pointed out by MarekR you do not need the lambda. The function is simpler like this:

#include <iostream>


template <typename stream, char Sep = ' ', class... Args >
stream& print(stream& out,Args&&... args)
{
    return ((out << args << Sep) , ...) << '\n';
}

int main()
{
    print(std::cout,"a", 'b', 3, 4.0, 5.0f, true);
}

Upvotes: 3

Related Questions