使用构造函数的可变参数中的其他模板类执行模板类的初始化 < >我想在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}}};
 }