【问题标题】:Convert initializer_list to variadic templates将 initializer_list 转换为可变参数模板
【发布时间】:2017-08-07 14:58:50
【问题描述】:

我使用了一个名为 fmt (http://fmtlib.net/latest/) 的格式化库。

其中一种可能的用途是:

fmt::format("Hello, {name}! The answer is {number}. Goodbye, {name}.", fmt::arg("name", "World"), fmt::arg("number", 42));

我想将此调用包装在一个函数中,我将其称为:

myFunction(myString, {"name", "World"}, {"number", 42});

对于任何个参数。

到现在为止,我只成功地做了一个可以用一对列表调用的函数:

myFunction(myString, std::make_pair("name", "World"), std::make_pair("number", 42));

功能:

std::string myFunction(const char* str, const Args&... rest) const
{
    return fmt::format(mLocale.getPOILabel(label), fmt::arg(rest.first, rest.second)...);
}

但我不想使用对。

我该怎么办?

PS : fmt::arg 不能在函数之间传递。

【问题讨论】:

  • 可以用模板化的构造函数定义一个类,即template<typename T> arg(const char *name, T &&value),然后{"number", 42}将成功地使用统一的初始化语法绑定到该类,并构造它。但是,我想不出一种方法来定义一个采用args 的可变参数列表的函数。好像参数包不喜欢大括号统一初始化语法...
  • 您的 PS 不可能是真的,因为您将它们传递给 fmt::format。我希望它只通过右值引用接收它们

标签: c++ c++11 variadic-templates variadic fmt


【解决方案1】:

不完全是你问的,因为你必须把你的函数称为

myFunction(myString, "name", "World", "number", 42);

而不是

myFunction(myString, {"name", "World"}, {"number", 42});

但以下应该是示例(抱歉,baz() 未经测试)

#include <tuple>
#include <string>
#include <utility>
#include <iostream>

// fmt headers

template <typename ... Ps>
std::string baz (char const * frmt,
                 std::pair<char const *, Ps> const & ... ps)
 { return fmt::format(frmt, fmt::arg(ps.first, ps.second)...); }

template <typename ... Ts, std::size_t ... Is>
std::string bar (char const * frmt, std::tuple<Ts...> const & t,
                 std::index_sequence<Is...> const &)
 { return baz(frmt, std::get<Is>(t)...); }

template <typename ... Ts>
std::string foo (char const * frmt, std::tuple<Ts...> const & t)
 { return bar(frmt, t, std::make_index_sequence<sizeof...(Ts)>{}); }

template <typename ... Ts, typename P1, typename P2, typename ... Args>
std::string foo (char const * frmt, std::tuple<Ts...> const & t,
                 P1 const & p1, P2 const & p2, Args const & ... args)
 { return foo(frmt, 
      std::tuple_cat(t, std::make_tuple(std::make_pair(p1, p2))), args...); }

template <typename ... Args>
std::string myFunction (char const * frmt, Args const & ... args)
 { return foo(frmt, std::tuple<>{}, args...); }

int main()
 {
   myFunction("format", "name", "World", "number", 42);
 }

注意这个例子使用std::index_sequencestd::make_index_sequence(),所以从C++14开始编译;但是很容易为这个类创建一个替代品,这个函数也可以与 C++11 一起使用。

【讨论】:

    【解决方案2】:

    尝试移动 fmt::arg 的结果,而不是复制或传递 const 引用。

    template<typename ... Args>
    std::string myFunction(const char* str, Args&&... rest) const
    {
        return fmt::format(mLocale.getPOILabel(label), std::forward<Args...>(rest)...);
    }
    
    myFunction(myString, fmt::arg("name", "World"), fmt::arg("number", 42));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-30
      • 1970-01-01
      • 2011-07-11
      • 2013-10-13
      • 2020-08-25
      相关资源
      最近更新 更多