用于创建字符串的 Variadic 模板函数
Variadic template function to create string
我是可变参数模板函数的新手。我写了一个简单的 class、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:
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 个重载中的 none 可以转换所有参数类型
我这样调用函数:
int main()
{
int age;
std::cin >> age;
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...);
}
还为 const char* 添加特化:
std::string Stringify(const char* value)
{
return mString += value;
}
现在您的问题是 const char[2]
被传递给 to_string
,但是 to_string
没有接受该输入的重载。通过将 to_string
替换为 Stringify
,可以将适当的重载用于参数包中的第一个参数。
错误的原因是,字符串文字("I"
、" am "
、" years "
、"old"
)是常量char
的数组(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
[=38= 时才启用]
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;
}
我是可变参数模板函数的新手。我写了一个简单的 class、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:
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 个重载中的 none 可以转换所有参数类型
我这样调用函数:
int main()
{
int age;
std::cin >> age;
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...);
}
还为 const char* 添加特化:
std::string Stringify(const char* value)
{
return mString += value;
}
现在您的问题是 const char[2]
被传递给 to_string
,但是 to_string
没有接受该输入的重载。通过将 to_string
替换为 Stringify
,可以将适当的重载用于参数包中的第一个参数。
错误的原因是,字符串文字("I"
、" am "
、" years "
、"old"
)是常量char
的数组(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
[=38= 时才启用]
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;
}