使用构造函数的可变参数中的其他模板类执行模板类的初始化 < >我想在C++中创建一个简单的HTML DOM生成器,并决定用模板化的代码>标签>代码>来描述这个标签的类型。 < P>我已经使用其他方法在C++中创建DOM,但有一些成功,但是设计不能处理原始字符串,所以移动到模板化类可以帮助我使用模板特化来处理它(标签< /代码>)。
现在的问题是使用可变模板将标记嵌套在其构造函数中。我已经能够用使用构造函数的可变参数中的其他模板类执行模板类的初始化 < >我想在C++中创建一个简单的HTML DOM生成器,并决定用模板化的代码>标签>代码>来描述这个标签的类型。 < P>我已经使用其他方法在C++中创建DOM,但有一些成功,但是设计不能处理原始字符串,所以移动到模板化类可以帮助我使用模板特化来处理它(标签< /代码>)。,c++,constructor,c++17,variadic-templates,template-argument-deduction,C++,Constructor,C++17,Variadic Templates,Template Argument Deduction,现在的问题是使用可变模板将标记嵌套在其构造函数中。我已经能够用节点实现它,它保存根级别的标记,但是标记嵌套中的任何标记都是不可能的 #包括 #包括 #包括 #包括 命名空间web{ 枚举类属性{charset,name,content,http_equiv,rel,href,id,src,lang}; 使用attribute=std::pair; 使用属性_type=std::map; const auto none=属性_type{}; enum tag_name{html,head,meta
节点
实现它,它保存根级别的标记,但是标记嵌套中的任何标记都是不可能的
#包括
#包括
#包括
#包括
命名空间web{
枚举类属性{charset,name,content,http_equiv,rel,href,id,src,lang};
使用attribute=std::pair;
使用属性_type=std::map;
const auto none=属性_type{};
enum tag_name{html,head,meta,title,link,body,div,script,plain,p,h1,span};
模板结构节点{
整数增量;
std::tuple标签;
显式节点(const int incr,Tags…tggs)
:增量{incr},标记{std::make_tuple(tggs…)}{}
};
模板结构标记{
属性类型属性;
std::tuple标签;
显式标记(属性类型atts、标记…tggs)
:属性{atts.begin(),atts.end()},标记{std::make_tuple(tggs…){
}
};
模板结构标记{
std::字符串内容;
显式标记(std::string val):内容{std::move(val)}{
};
}//名称空间web
int main(){
使用命名空间web;
节点page1{2};
节点page2{2,标记{none}};
节点page3{2,标记{{{attrs::lang,“en”}};
节点page4{2,标记{{{attrs::name,“viewport”},
{attrs::content,
“宽度=设备宽度,初始刻度=1.0”}};
节点page5{2,tag{none},tag{none},tag{“Hello World”};//但是这一行仍然按照预期编译和工作。。。
节点page6{1,tag{none,tag{none}}};//错误:没有用于初始化“tag”的匹配构造函数
}
我想知道如何在节点类内聚合标记,但在
标记
类内无法聚合标记,如果可能,我将能够解决此问题。这似乎是模板类类型推断的问题。一个简单的函数包装器(或C++17演绎指南)可以消除歧义
不管怎样,现在开始(这在gcc 8.3中C++17模式下工作):
#包括
#包括
#包括
#包括
命名空间web
{
枚举类属性{charset,name,content,http_equiv,rel,href,id,src,lang};
使用attribute=std::pair;
使用属性_type=std::map;
const auto none=属性_type{};
enum tag_name{html,head,meta,title,link,body,div,script,plain,p,h1,span};
模板
结构节点
{
整数增量;
std::tuple标签;
显式节点(const int incr,Tags…tggs):增量{incr},Tags{tggs…}{
};
模板
结构标签
{
属性类型属性;
std::tuple标签;
显式标记(const-attribute_-type&atts,Tags…tggs):属性(atts),标记(tggs…{}
};
模板
结构标签
{
std::字符串内容;
显式标记(std::string val):内容(std::move(val)){}
};
模板
自动生成节点(int incr,Args&…Args)
{
返回节点(incr,std::forward(args)…);
}
模板
自动生成标记(常量属性类型和附件、参数和…参数)
{
返回标签(atts,std::forward(args)…);
}
}//名称空间web
int main(){
使用命名空间web;
节点page1{2};
节点page2{2,标记{none}};
节点page3{2,标记{{{attrs::lang,“en”}};
节点page4{2,标记{{{attrs::name,“viewport”},
{attrs::content,
“宽度=设备宽度,初始刻度=1.0”}};
节点page5{2,标记{none},标记{none},标记{“Hello World”};
auto page6=make_节点(1,make_标记(无,make_标记(无));//现在可以工作-使用make函数
}
代码中的问题是,C++17中引入的演绎指南只能演绎所有的模板参数
这么叫
node page2{2, tag<html>{none}};
因为,对于标记
,在无
之后有一个参数,所以变量列表标记…
不是空的,但不能是空的(通过隐式推导指南自动),因为您已经解释了第一个模板参数(span
)
正如Cruz Jean所建议的,添加make_tag()
函数显然可以解决这个问题,但我建议您使用一种不同的解决方案,即使用自动推断指南
首先,为tag\u name
s定义一个包装类w
template <tag_name>
struct w
{ };
第二个用于一般情况(也不是空的内部标记
列表),接收w
元素,允许对T
explicit tag (w<T>, attribute_type atts, Tags... tggs)
: attributes{std::move(atts)}, tags{tggs...}
{ }
下面是一个完整的编译示例
#include <map>
#include <string>
#include <tuple>
#include <utility>
namespace web
{
enum class attrs
{ charset, name, content, http_equiv, rel, href, id, src, lang };
using attribute = std::pair<attrs, std::string>;
using attribute_type = std::map<attrs, std::string>;
const auto none = attribute_type{};
enum tag_name
{ html, head, meta, title, link, body, div, script, plain, p, h1, span };
template <typename... Tags>
struct node
{
int increment;
std::tuple<Tags...> tags;
explicit node (int const incr, Tags ... tggs)
: increment{incr}, tags{tggs...}
{ }
};
template <tag_name>
struct w
{ };
template <tag_name T, typename ... Tags>
struct tag
{
attribute_type attributes;
std::tuple<Tags...> tags;
explicit tag (attribute_type atts)
: attributes{std::move(atts)}
{ }
explicit tag (w<T>, attribute_type atts, Tags... tggs)
: attributes{std::move(atts)}, tags{tggs...}
{ }
};
template <>
struct tag<plain>
{
std::string content;
explicit tag (std::string val) : content{std::move(val)}
{ }
};
} // namespace web
int main ()
{
using namespace web;
node page1{2};
node page2{2, tag<html>{none}};
node page3{2, tag<html>{{{attrs::lang, "en"}}}};
node page4{2, tag<html>{{{attrs::name, "viewport"},
{attrs::content, "width=device-width, initial-scale=1.0"}}}};
node page5{2, tag<head>{none}, tag<body>{none},
tag<plain>{"Hello World"}};
node page6{1, tag{w<span>{}, none, tag<h1>{none}}};
}
#包括
#包括
#包括
#包括
命名空间web
{
枚举类属性
{charset,name,content,http_equiv,rel,href,id,src,lang};
使用attribute=std::pair;
使用属性_type=std::map;
const auto none=属性_type{};
枚举标记名称
{html,head,meta,title,link,body,div,script,plain,p,h1,span};
模板
结构节点
{
整数增量;
std::tuple标签;
显式节点(int const incr,Tags…tggs)
:增量{incr},标记{tggs…}
{ }
};
模板
结构w
{ };
模板
结构标签
{
属性类型属性;
std::tuple标签;
显式标记(属性类型atts)
:属性{std::move(atts)}
{ }
显式标记(w,属性类型atts,标记…tggs)
:属性{std::move(atts)
explicit tag (attribute_type atts)
: attributes{std::move(atts)}
{ }
explicit tag (w<T>, attribute_type atts, Tags... tggs)
: attributes{std::move(atts)}, tags{tggs...}
{ }
tag<html>{none}
tag{w<html>{}, none}
tag{w<span>{}, none, tag<h1>{none}}
#include <map>
#include <string>
#include <tuple>
#include <utility>
namespace web
{
enum class attrs
{ charset, name, content, http_equiv, rel, href, id, src, lang };
using attribute = std::pair<attrs, std::string>;
using attribute_type = std::map<attrs, std::string>;
const auto none = attribute_type{};
enum tag_name
{ html, head, meta, title, link, body, div, script, plain, p, h1, span };
template <typename... Tags>
struct node
{
int increment;
std::tuple<Tags...> tags;
explicit node (int const incr, Tags ... tggs)
: increment{incr}, tags{tggs...}
{ }
};
template <tag_name>
struct w
{ };
template <tag_name T, typename ... Tags>
struct tag
{
attribute_type attributes;
std::tuple<Tags...> tags;
explicit tag (attribute_type atts)
: attributes{std::move(atts)}
{ }
explicit tag (w<T>, attribute_type atts, Tags... tggs)
: attributes{std::move(atts)}, tags{tggs...}
{ }
};
template <>
struct tag<plain>
{
std::string content;
explicit tag (std::string val) : content{std::move(val)}
{ }
};
} // namespace web
int main ()
{
using namespace web;
node page1{2};
node page2{2, tag<html>{none}};
node page3{2, tag<html>{{{attrs::lang, "en"}}}};
node page4{2, tag<html>{{{attrs::name, "viewport"},
{attrs::content, "width=device-width, initial-scale=1.0"}}}};
node page5{2, tag<head>{none}, tag<body>{none},
tag<plain>{"Hello World"}};
node page6{1, tag{w<span>{}, none, tag<h1>{none}}};
}