用于创建字符串的可变参数模板函数



我是可变参数模板函数的新手。我写了一个简单的类,StringStream,它有一个可变参数模板函数,可以从变量模板参数(字符串、整数等(创建一个std::string

#include <string>
#include <sstream>
class StringStream
{
public:
StringStream() = default;
~StringStream() = default;
template<typename T>
std::string Stringify(const T &value)
{
mStream << value;
return mStream.str();
}
template<typename T, typename... Ts>
std::string Stringify(const T& value, Ts... values)
{
mStream << value;
return Stringify(values...);
}
private:
std::stringstream mStream;
};

我现在要做的是在StringStream中使用std::string成员而不是std::stringstream并从Stringify()的参数构建字符串。对于不std::string的参数,我想转换为带有std::to_string()的字符串,否则我只是连接参数。我遇到了编译器错误。这是我修改后的类:

class StringStream
{
public:
StringStream() = default;
~StringStream() = default;
template<typename T>
std::string Stringify(const T &value)
{
mString += std::to_string(value);
return mString;
}
template<>
std::string Stringify<std::string>(const std::string& value)
{
mString += value;
}
template<typename... Ts>
std::string Stringify(const std::string& value, Ts... values)
{
mString += value;
return Stringify(values...);
}
template<typename T, typename... Ts>
std::string Stringify(const T& value, Ts... values)
{
mString += std::to_string(value);
return Stringify(values...);
}
private:
std::string mString;
};

我的编译器错误说:

错误 C2665:"std::to_string":9 个重载都无法转换所有参数类型

我像这样调用函数:

int main()
{
int age;
std::cin >> age;
StringStream ss;
std::cout << ss.Stringify("I", " am ", age, " years ", "old") << std::endl;
}

有什么办法可以解决这个问题吗?

错误的原因是字符串文字("I"" am "" years ""old"(是常数chars(char const [N],对于某些N(的数组。您可以将它们拦截为char const *,但不能std::string

我想有点跑题了,但我给你两个建议:

(1(将Stringify()除以两个函数:可变参数,public,调用private函数(toStr(),在下面的例子中(进行单参数转换

(2(避免递归的可变参数版本的Stringify()而只需使用包扩展。

我的意思是。。。您可以按如下方式编写Stringify()

template <typename... Ts>
std::string Stringify (Ts const & ... vals)
{
using unused = int[];
(void)unused { 0, (mString += toStr(vals), 0)... };
return mString;
}

或者,如果您可以使用 C++17,请使用模板折叠

template <typename... Ts>
std::string Stringify (Ts const & ... vals)
{ return ((mString += toStr(vals)), ...); }

对于toStr(),我提出了一个使用std::to_string()但仅在模板T类型不可转换为std::string时才启用的模板版本

template <typename T>
typename std::enable_if<
false == std::is_convertible<T, std::string>::value,
std::string>::type toStr (T const & val)
{ return std::to_string(val); }

以及接受std::string的非模板版本

std::string toStr (std::string const & val)
{ return val; }

这样,如果参数可以直接转换为std::string(std::string或可用于构造std::string的另一种类型(,则调用非模板版本;否则称为模板版本。

以下是完整的编译示例

#include <iostream>
#include <type_traits>
class StringStream
{
private:
std::string mString;
template <typename T>
typename std::enable_if<
false == std::is_convertible<T, std::string>::value,
std::string>::type toStr (T const & val)
{ return std::to_string(val); }
std::string toStr (std::string const & val)
{ return val; }
public:
StringStream() = default;
~StringStream() = default;
template <typename... Ts>
std::string Stringify (Ts const & ... vals)
{
using unused = int[];
(void)unused { 0, (mString += toStr(vals), 0)... };
return mString;
}
};
int main ()
{
int age = 42;
StringStream ss;
std::cout << ss.Stringify("I", " am ", age, " years ", "old") << std::endl;
}

你在里面打电话to_string

template<typename T>
std::string Stringify(const T &value)
{
mString += std::to_string(value);
return mString;
}

因此,您可以从Stringify(const T& value, Ts... values)中删除to_string,并将其替换为Stringify

template<typename T, typename... Ts>
std::string Stringify(const T& value, Ts... values)
{
mString += Stringify(value);
return Stringify(values...);
}

还添加了常量字符*的专用化:

std::string Stringify(const char* value)
{
return mString += value;
}

现场演示

现在你的问题是const char[2]被传递to_string,但to_string没有接受该输入的重载。通过将to_string替换为Stringify可以将适当的重载用于参数包中的第一个参数。

相关内容

  • 没有找到相关文章

最新更新