Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

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:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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);
}

>Solution :

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);
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading