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

Variadic templates and constraints

I have a variadic template function that takes as parameters file name, delimiter, and non-specified number of containers as columns. This function then parses to file all values in containers that represent columns and between all values put delimiter.

bool parseToFile (const std::string& file, const char delimiter, auto&... columns)
{
    bool done {false};
    std::ofstream out;
    out.open (file, std::ios::out | std::ios::trunc);
    if (!out)
    {
        done = false;
        std::cout << "SaveFile: Cannot open file: " << file << "!" ;
        std::cout << std::strerror (errno) << std::endl;
    }
    else
    {
        std::size_t maxContainerSize {0};
        auto maxSize = [&maxContainerSize] (std::size_t containerSize)
        {
            maxContainerSize = std::max (maxContainerSize, containerSize);
        };
        (maxSize (columns.size()), ...);
        std::size_t i {0};
        auto implementation = [&i, delimiter, &out] (auto & cont, std::size_t s)
        {
            if (i < cont.size())
                out << cont[i];

            out << delimiter;
        };
        for (; i < maxContainerSize; ++i)
        {
            (implementation (columns, columns.size()), ...);
            out << "\n";
        }
        out << std::flush;
        done = true;
    return done;
}

This works as intended correctly.

But this template has several constraints releating to what can be parameter pack "columns"

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

  • it should be a container
  • any container should overload operator [] to get access to objects (eg. std::vector, std::deque)
  • any object in the container should have operator << to be able to work with iostream

How should I change my code to implement this constraint?

I have tried this:

template <template <typename, typename> class Container,
          typename Value,
          typename Allocator = std::allocator<Value>>
concept containerHasPrintable = requires (std::ostream& out, Container<Value,Allocator>& data)
{
    out << data[0];
};

// and definition:
bool parseToFile (const std::string& file, const char delimiter, containerHasPrintable&... columns);

But this does not work. GCC 13.1

main.cpp|80|error: wrong number of template arguments (1, should be at least 2)| "80 – function"
main.cpp|40|note: provided for ‘template<template<class, class> class Container, class Value, class Allocator> concept containerHasPrintable’| "40 – concept"
main.cpp|80|error: expansion pattern ‘int&’ contains no parameter packs|

How can I constrain the template?


EDIT: Added solution:

template <typename Container>
concept PrintableContainer = requires (std::ostream& out, Container& data)
{
    out << data[0];
};

// and template
bool parseToFile (const std::string& file, const char delimiter, PrintableContainer auto&... columns) // ....

>Solution :

This:

template <template <typename, typename> class Container,
          typename Value,
          typename Allocator = std::allocator<Value>>
concept containerHasPrintable = /* ... */;

Is a concept that is constraining three things: a template and two types. But that’s not actually what you want – you want a concept that is constraining one thing: a type.

So what you want to write is just that:

template <typename Container>
concept PrintableContainer = requires (std::ostream& out, Container& data)
{
    out << data[0];
};

Note that none of the other stuff in your concept is actually relevant – you don’t need the container to specifically look like C<V, A> anyway – and this just arbitrarily rejects some other types that would otherwise work (like, say, std::string).

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