gpt4 book ai didi

c++ - 正确使用 C++ 可变参数模板

转载 作者:行者123 更新时间:2023-11-30 02:48:02 25 4
gpt4 key购买 nike

我目前正在从事一个需要生成简单 XML 的对象的项目。我对 XML 很陌生,还在学习 C++。
我想要实现的是一个可以在代码中这样调用的函数:

std::string xml = createXML("name", "attribute1", 10, "attribute2",
"stringForAttrib2");

在这一行之后,xml字符串应包含如下内容:< parameter name="name" attribute1=10 attribute2="stringForAttrib2" />

函数必须接受尽可能多的属性,并且名称不是可选的。我试过这样的事情:

template<typename ...Attributes>
void XMLGenerator::createXML(std::string param_name, Attributes... attributes)
{
std::ostringstream xmlString;
xmlString << "<parameter name=\"" << param_name << "\" ";
createXML(xmlString, attributes...);
xmlString << "/>";
m_xmlString << xmlString;
}

template<typename ...Attributes, typename DataType>
void XMLGenerator::createXML(std::ostringstream &xmlString,
std::string attribut_name, DataType data,
Attributes... attributes)
{
xmlString << attribut_name << "=\"" << data << "\" ";
createXML(xmlString, attributes...);
}

void XMLGenerator::addParameter(std::ostringstream &xmlString){ }

g++ 不喜欢它:

undefined reference to `void XMLGenerator::createXML< char const*, int, char const*, >char const*>(std::string, char const*, int, char const*, char const*)'

为什么不是第一个 createXML方法调用 ?

此外,如果我的问题有更简单的解决方案,我也会感兴趣。

最佳答案

这里是solution ,前向声明很重要,请注意 std::forward 的使用与通用引用 Ts&& 相结合:

#include <iostream>
#include <string>

// =================================
// print_attribs parameter usage : ( os, name0, val0, ..., nameN, valN )
// name is char const* or std::string
// val can be anything compatible with os operator<<
// print_attribs is specialize for char const* and std::string values to enclose them with double quotes.

template < typename T, typename... Ts> void print_attribs( std::ostream & os, char const * name, T&& val, Ts&&... ts );
template < typename... Ts> void print_attribs( std::ostream & os, char const * name, char const * val, Ts&&... ts );
template < typename... Ts> void print_attribs( std::ostream & os, char const * name, std::string const & val, Ts&&... ts );

template < typename T, typename... Ts> void print_attribs( std::ostream & os, std::string const & name, T&& val, Ts&&... ts );
template < typename... Ts> void print_attribs( std::ostream & os, std::string const & name, char const * val, Ts&&... ts );
template < typename... Ts> void print_attribs( std::ostream & os, std::string const & name, std::string const & val, Ts&&... ts );

void print_attribs( std::ostream & os ) { }

template < typename... Ts>
void print_attribs( std::ostream & os, char const * name, char const * val, Ts&&... ts ) {
os << " " << name << "=\"" << val << "\"";
print_attribs( os, std::forward<Ts>(ts)... );
}

template < typename... Ts>
void print_attribs( std::ostream & os, std::string const & name, char const * val, Ts&&... ts ) {
print_attribs( os, name.c_str(), val, std::forward<Ts>(ts)... );
}

template < typename... Ts>
void print_attribs( std::ostream & os, char const * name, std::string const & val, Ts&&... ts ) {
os << " " << name << "=\"" << val << "\"";
print_attribs( os, std::forward<Ts>(ts)... );
}

template < typename... Ts>
void print_attribs( std::ostream & os, std::string const & name, std::string const & val, Ts&&... ts ) {
print_attribs( os, name.c_str(), val, std::forward<Ts>(ts)... );
}

template < typename T, typename... Ts>
void print_attribs( std::ostream & os, char const * name, T&& val, Ts&&... ts ) {
os << " " << name << "=" << std::forward<T>(val);
print_attribs( os, std::forward<Ts>(ts)... );
}

template < typename T, typename... Ts>
void print_attribs( std::ostream & os, std::string const & name, T&& val, Ts&&... ts ) {
print_attribs( os, name.c_str(), std::forward<T>(val), std::forward<Ts>(ts)... );
}

template < typename... Ts>
void print( std::ostream & os, char const * name, Ts&&... ts ) {
static_assert( sizeof...(ts) % 2 == 0, "arguments must be paired of string and value" );
os << "<parameter name=\"" << name << "\"";
print_attribs( os, std::forward<Ts>(ts)... );
os << " />";
}

template < typename... Ts>
void print( std::ostream & os, std::string const & name, Ts&&... ts ) {
static_assert( sizeof...(Ts) % 2 == 0, "Ts must be even, as they are pairs of name and value" );
print( os, name.c_str(), std::forward<Ts>(ts)... );
}

int main() {
auto endl = [] { std::cout << std::endl; };
print( std::cout, "example", "foo", 10 ); endl();
print( std::cout, "example", "foo", 10, "bar", "bare" ); endl();
print( std::cout, "example", "foo", 10, "bar", 3.14f ); endl();
print( std::cout, "example", "foo", 10, "bar", 3.14f, "bar", 3.14f ); endl();
print( std::cout, "example", "foo", 10, "bar", "bare", "baz", 3.14f ); endl();
}

编辑:添加了 static_assert of arguments count 和 char const* 替代方案以绕过不必要的 std::string 构造。

关于c++ - 正确使用 C++ 可变参数模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22286021/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com