使用初始值设定项列表的C++变量参数



假设下面的代码,它是一个很小的sprintf替代品。(_itoa等只是用来保持代码简短。(

#include <cstdlib>
#include <string>
class Arg {
public:
Arg(const std::string& s) :m_str(s) {}
Arg(const char* s) : m_str(s) {}
Arg(int digi, double number)  {char buf[128]; m_str = _gcvt(number, digi, buf);}
operator const std::string& ()const { return m_str; }
private:
std::string m_str;
};
class Format {
public:
Format(/*const char* format, */std::initializer_list<Arg> args); // see below
const std::string& str()const { return m_str; }
private:
std::string m_str;
};
Format::Format(/*const char* format, */std::initializer_list<Arg> args) {
auto arg = args.begin();
auto format = std::string(*arg++);
for(const char* c = format.c_str(); *c!=''; ++c) {
if(*c=='%') { m_str+=*arg++; }
else { m_str+=*c; }
}
}

int main() {
std::string test1 = Format{"test Double:% String:%", {5, 456.78}, "foo"}.str();
// I want to make this work. See the braces.
std::string test2 = Format("test Double:% String:%", {5, 456.78}, "foo").str();
return 0;
}

你看,我想传递参数,仅限于类型"Arg",但使用一个构造函数,该构造函数使用例如varadic模板,而不是initializer_list<>以获得更好的可读性。

我试过了:

template<typename... T>
Format(T&& ... args) : Format(std::forward<Args>(args)...) {}

但我得到了:

error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Format'
note: No constructor could take the source type, or constructor overload resolution was ambiguous

std::initializer_list需要{}而不是()

{5, 456.78}没有类型,无法推导模板。

保持语法旧重载方式的方法:

Format(Arg arg0) : Format(std::initializer_list{arg0});
Format(Arg arg0, Arg arg1) : Format({arg0, arg1});
Format(Arg arg0, Arg arg1, Arg arg2) : Format({arg0, arg1, arg2});
// ... Up to some limit

首先,您应该在成员初始值设定项列表中使用大括号,以转发到使用std::initializer_list的构造函数。

template<typename... T>
Format(T&& ... args) : Format{std::forward<T>(args)...} {}
//                           ^                        ^

其次,在给定Format("test Double:% String:%", {5, 456.78}, "foo")的情况下,不幸的是,像{5, 456.78}这样的支撑init列表无法在模板类型推导中推导出来,它没有类型。您可以像一样明确指定类型

std::string test2 = Format("test Double:% String:%", Arg(5, 456.78), "foo").str();
//                                                      ^         ^

您可以这样做:

template<typename... T>
Format(T&& ... args) : Format({std::forward<T>(args)...}) {}}

但在调用中,您应该手动指出第二个参数是Arg,如下所示:

std::string test2 = Format("test Double:% String:%", Arg{5, 456.78}, "foo").str();

示例

最新更新