Как передать не переменные значения в fmt::format?

Я играю с великолепной библиотекой fmt C++, чтобы форматировать строки более изящно.

И я хотел бы передать список переменных без переменных fmt::format, Это может быть std::vector, или же std::stringили что угодно, но оно всегда будет соответствовать строке формата.

Так fmt::format работает как:

std::string message = fmt::format("The answer is {} so don't {}", "42", "PANIC!");

Но то, что я хотел бы, это что-то вроде:

std::vector<std::string> arr;
arr.push_back("42");
arr.push_back("PANIC!");
std::string message = fmt::format("The answer is {} so don't {}", arr);

Есть ли способ / способ это сделать?

4 ответа

Решение

Добавьте дополнительный слой, что-то вроде:

template <std::size_t ... Is>
std::string my_format(const std::string& format,
                      const std::vector<std::string>& v,
                      std::index_sequence<Is...>)
{
    return fmt::format(format, v[Is]...);
}


template <std::size_t N>
std::string my_format(const std::string& format,
                      const std::vector<std::string>& v)
{
    return my_format(format, v, std::make_index_sequence<N>());
}

Использование будет:

std::vector<std::string> arr = {"42", "PANIC!"};
my_format<2>("The answer is {} so don't {}", arr);

С operator ""_format у вас может быть информация об ожидаемом размере во время компиляции

Вы можете привести аргументы в пользу vformat самостоятельно от вашего vector. Кажется, это работает:

std::string format_vector(std::string_view format,
    std::vector<std::string> const& args)
{
    using ctx = fmt::format_context;
    std::vector<fmt::basic_format_arg<ctx>> fmt_args;
    for (auto const& a : args) {
        fmt_args.push_back(
            fmt::internal::make_arg<ctx>(a));
    }

    return fmt::vformat(format,
        fmt::basic_format_args<ctx>(
            fmt_args.data(), fmt_args.size()));
}

std::vector<std::string> args = {"42", "PANIC!"};
std::string message = format_vector("The answer is {} so don't {}", args);

В текущей версии (8.1.1) возможно следующее;

      fmt::dynamic_format_arg_store<fmt::format_context> ds;

ds.push_back(42);
ds.push_back("PANIC");

std::string msg = fmt::vformat("The answer is {} so don't {}", ds);

Похоже, это невозможно без внесения изменений в библиотеку fmt. fmt::format звонки fmt::vformat который занимает fmt::format_args или же fmt::wformat_args объект, представляющий несколько аргументов, но единственный способ обеспечить format_args или же wformat_args Объекты передаются через другую переменную функцию, что означает, что число и типы аргументов должны быть известны во время компиляции.

Так что вы можете написать обертку, чтобы распаковать std::tuple или же std::array и передать его элементы fmt::formatпотому что количество и типы элементов в них известны во время компиляции. Но вы не можете сделать то же самое с std::vector, std::listи т. д., поскольку размер этих контейнеров может изменяться во время выполнения.

Другие вопросы по тегам