可变参数模板和约束

Tom*_*hal 3 c++ constraints variadic-templates c++20

我有一个可变参数模板函数,它将文件名、分隔符和非指定数量的容器作为参数作为列。然后,该函数解析并归档表示列的容器中的所有值,并在所有值之间放置分隔符。

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;
}
Run Code Online (Sandbox Code Playgroud)

这按预期正确工作。

但是这个模板有几个与参数包“列”相关的限制

  • 它应该是一个容器
  • 任何容器都应该重载运算符 [] 来访问对象(例如 std::vector、std::deque)
  • 容器中的任何对象都应该具有运算符 << 才能使用 iostream

我应该如何更改我的代码来实现这个约束?

我已经尝试过这个:

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);
Run Code Online (Sandbox Code Playgroud)

但这是行不通的。海湾合作委员会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|
Run Code Online (Sandbox Code Playgroud)

如何约束模板?

Bar*_*rry 5

这:

template <template <typename, typename> class Container,
          typename Value,
          typename Allocator = std::allocator<Value>>
concept containerHasPrintable = /* ... */;
Run Code Online (Sandbox Code Playgroud)

是一个限制件事的概念:模板和两种类型。但这实际上并不是您想要的 - 您想要一个限制件事的概念:类型。

所以你想写的就是:

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

请注意,您的概念中的其他内容实际上都不相关 - 您不需要容器看起来特别像C<V, A>- 这只是武断地拒绝了一些其他可以工作的类型(例如,std::string)。

  • 顺便说一句,“data.size()”也应该是必需的。 (2认同)