Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/155.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
关于C+中类模板参数推导的问题+;17 我试图理解(当前的C++草案标准N4606中所采用的“类模板的模板参数推导”文件。< /P>_C++_Templates_Language Lawyer_Template Meta Programming_C++17 - Fatal编程技术网

关于C+中类模板参数推导的问题+;17 我试图理解(当前的C++草案标准N4606中所采用的“类模板的模板参数推导”文件。< /P>

关于C+中类模板参数推导的问题+;17 我试图理解(当前的C++草案标准N4606中所采用的“类模板的模板参数推导”文件。< /P>,c++,templates,language-lawyer,template-meta-programming,c++17,C++,Templates,Language Lawyer,Template Meta Programming,C++17,我相信我理解它在最简单的情况下的工作原理,即模板名称标识单个模板: template<class T> struct S { S(T); S(const std::vector<T>&); }; int main() { std::vector<int> v; auto s = S(v); } 并对虚拟调用执行重载解析 Sctor(v) 要确定在这种情况下,我们需要调用虚构的Sctor(const std::vec

我相信我理解它在最简单的情况下的工作原理,即模板名称标识单个模板:

template<class T>
struct S {
    S(T);
    S(const std::vector<T>&);
};

int main()
{
    std::vector<int> v;
    auto s = S(v);
}
并对虚拟调用执行重载解析

Sctor(v)
要确定在这种情况下,我们需要调用虚构的
Sctor(const std::vector&)[with T=int]
。这意味着我们最终调用了
S::S(const std::vector&)
,一切都很好

我不明白的是,在存在部分专业化的情况下,这是如何工作的

template<class T>
struct S {
    S(T);
};

template<class T>
struct S<std::list<T>> {
    S(const std::vector<T>&);
};

int main()
{
    std::vector<int> v;
    auto s = S(v);
}
模板
结构{
S(T);
};
模板
结构{
S(常数std::向量&);
};
int main()
{
std::向量v;
自动s=s(v);
}
这里我们直观地希望调用
S::S(const std::vector&)
。这就是我们真正得到的吗?这是在哪里指定的

基本上,我不能直观地理解P0091r3所说的“由模板名称指定的类模板”是什么意思:这是指主模板,还是包括所有部分专门化和显式完全专门化

(我也不明白P0091r3对§7.1.6.2p2的更改是如何使用注入的类名(如

模板
结构迭代器{
迭代器和运算符++(int){
迭代器结果=*this;//注入的类名或占位符?
//...
}
};
但这是一个完全不同的问题。)



现有版本的Clang或GCC是否支持类模板推导和显式推导指南(可能在
-f
标志下,如
-fconcepts
is)?如果是这样的话,我可以在现实生活中反复使用其中一些例子,或许可以消除一半的困惑。

我想说,P0091目前的措辞在这方面的规定不足。它确实需要弄清楚它是仅仅是主类模板还是包含所有专门化的构造函数

template<class T>
struct S {
    S(T);
};

template<class T>
struct S<std::list<T>> {
    S(const std::vector<T>&);
};

int main()
{
    std::vector<int> v;
    auto s = S(v);
}
也就是说,我相信P0091的意图是部分专业化不参与论点推导。该特性允许编译器决定类的模板参数是什么。然而,选择部分专门化的是那些模板参数实际上是什么。获取
S
专门化的方法是在
S
的模板参数列表中使用
std::list


如果要使特定参数使用特定的专门化,则应使用扣减指南。毕竟,这就是他们的目的。

这在某种程度上被提案忽略了,但我认为其目的是只考虑主类模板的构造函数。这方面的证据是新的[class.template.reduction]具有:

  • 对于由模板名称指定的类模板的每个构造函数,具有以下属性的函数模板是候选的:[…]
如果我们谈论的是“the”类模板,那么这就是主类模板,特别是当通过名称查找([temp.class.spec]/6)找不到类模板的部分专门化时。这也是原型实现(见下文)的表现

在本文中,“隐式推导指南的优缺点”一节中考虑了类模板的部分专门化,但出于对主类模板中的构造函数可能触发硬(非SFINAE)错误的担忧:

模板结构X{
使用ty=T::type;
静态自动foo(){return typename T::type{};
X(ty)#1
X(decltype(foo());#2
X(T);
};
模板
结构X{
X(…);
};
X{(int*)0};
您要求考虑类模板部分专门化构造函数的请求表面上是合理的,但请注意,这可能会导致歧义:

template<class T> struct Y { Y(T*); };
template<class T> struct Y<T*> { Y(T*); };
Y y{(int*) 0};
模板结构Y{Y(T*);};
模板结构Y{Y(T*);};
Y{(int*)0};
隐式生成的演绎指南可能需要通过类模板的专门化进行排名(作为平局破坏者)

如果您想尝试原型实现,作者已经在github上发布了他们的clang分支:


论文中的讨论(“关于注入类名称的说明”)表明注入类名称优先于模板名称;增加措辞以确保:

模板名称应命名不是注入类名称的类模板


到目前为止,没有任何主要编译器(可能根本没有编译器)支持构造函数的模板参数推断。如果我没有弄错的话,可能在某个地方有一个用来收集实现经验的铿锵分支,但我甚至不确定它是否在网上的任何地方都可用。重新注入的类名:我看到了这句话,但仍然无法理解它是否意味着“如果模板名是注入的类名,那么程序的格式就不正确。”或者“模板名后跟一个开括号永远不会被解释为注入的类名”,或者。。。事实上,您的解释(“模板名称应尽可能解释为注入类名称”)与我的完全相反P@Quuxplusone[temp.local]/1在将注入的类名视为模板名时枚举。
template<class T> struct X {
   using ty = T::type;
   static auto foo() { return typename T::type{} };
   X(ty); #1
   X(decltype(foo())); #2
   X(T);
};
template<class T>
struct X<T*> { 
   X(...);
};
X x{(int *)0};
template<class T> struct Y { Y(T*); };
template<class T> struct Y<T*> { Y(T*); };
Y y{(int*) 0};