考虑下面粘贴的代码。我定义了一个非常简单的类,编译器为其生成一个隐式推导指南,这样就可以在没有显式模板参数的情况下构造它。但是,模板参数推导不适用于从仅直接转发到目标类的简单别名模板构造对象:
template< typename A, typename B >
struct Foo {
Foo( A const &a, B const &b )
: a_(a), b_(b)
{ }
A a_;
B b_;
};
template< typename A, typename B >
using Bar = Foo<A, B>;
auto foobar() {
Foo r{1, 2};
Bar s{3, 4};
// ../src/geo/vector_test_unit.cpp: In function 'auto foobar()':
// ../src/geo/vector_test_unit.cpp:16:6: error: missing template arguments before 's'
// Bar s{3, 4};
// ^
return 1;
}
正如您从上面的代码注释中看到的,g给了我一个关于使用别名模板而没有模板参数的错误。我希望在这样的例子中,模板参数推导会被转发。
所以,我的问题是:这是通过明示设计目前的措辞来对班级模板的论点进行演绎的建议吗?或者这是一个未完成的特性还是当前g实现中的bug?对于提案的作者或ISO委员会来说,这将是一个更大的问题,但如果他们中的任何人看到了这一点:是否希望该功能的最终措辞包括允许像这样的别名模板也为他们生成隐式指南?
我可以理解,由于别名模板可以有任何类型的模板参数,编译器可能并不总是能够成功地推断出目标类模板参数,但在这样的情况下,我希望编译器能够在相同的这样就可以直接为目标类。
几天前,我使用head构建的gcc,使用--std=C1z
。完整的版本信息是:gcc版本7.0.0 20161201(实验版)(自制gcc头---带jit)
从http://en.cppreference.com/w/cpp/language/template_argument_deduction,“别名模板永远不会推导出来。”所以,这是有意为之。
这是我们在制定提案时考虑的一个特性,但它最终被从C17特性集中删除,因为我们还没有足够好的设计。特别是,关于如何从别名模板中选择和转换演绎指南到别名模板的演绎指南,有一些微妙之处。如果别名模板不是另一个模板的简单别名,那么如何操作还有一些悬而未决的问题。一些例子:
template<typename T> struct Q { Q(T); }; // #1
template<typename T> struct Q<T*> { Q(T); }; // #2
template<typename U> using QP = Q<U*>;
int *x;
Q p = x; // deduces Q<int*> using #1, ill-formed
QP q = x; // deduces Q<int*> using #1, or
// deduces Q<int**> using #2?
template<typename T> Q(T) -> Q<T>; // #3
QP r = x; // can we use deduction guide #3 here?
template<typename T> Q(T*) -> Q<T**>; // #4
int **y;
QP s = y; // can we use deduction guide #4 here?
template<typename T> struct A { typedef T type; struct Y {}; };
template<typename T> using X = typename A<T>::type;
template<typename T> using Y = typename A<T>::Y;
X x = 4; // can this deduce T == int?
Y y = A<int>::Y(); // can this deduce T == int?
上面的问题有很好的答案,但解决它们会增加复杂性,而且似乎更可取的做法是不允许对C17的别名模板进行推断,而不是匆忙地做一些有缺陷的事情。
更新[C 20]:在C 20中重新讨论了这个主题,我们批准了P1814R0,它允许对别名模板进行类模板参数推断。
原来的例子现在是有效的。对于上述示例:
>
template<typename T> Q(T) -> Q<T>;
然后通过推导Q
(Q)指南的右侧,将其转换为别名模板
QP
的指南
template<typename U> Q(U*) -> Q<U*>;
// ... which is effectively ...
template<typename U> QP(U*) -> QP<U>;
// ... except that explicit deduction guides are not
// permitted for alias templates
然后,该指南用于推导
q
的类型,该类型推导出U
=int
,因此q
的类型是Q
<代码> r>代码>的初始化考虑了演绎指南>3,如上所述转化为<代码> QP < /代码>的指南。
<代码> S/<代码>的初始化考虑了演绎指南>4;推导
Q
template<typename T> Q(T*) -> Q<T**>;
原样,但添加一个约束,即推导的结果必须匹配
QP
的形式。然后我们推导出T
=int
,代之以计算Q的结果类型
仅当别名模板的右侧是一个简单的模板id(格式为
maybe::stuff::templatename)时,才支持别名模板的CTAD
另一个有用的可能示例:(伪代码)
已编辑(原始问题只有int A,int B): 模板参数推断在两个专门化之间比较的#参数相同时按预期工作,但在它们不同时失败(因为在其中一个专门化中包含默认参数)。 例如:为什么模板参数推导在一种情况下与另一种情况下失败,有人能指出解释这一点的任何资源/标准吗? 错误:模糊模板实例化'类Foo
如果我没有理解错的话,类模板定义了一个函数,所以当我调用时,编译器有可能进行隐式强制转换,但是在函数模板的情况下,此时没有函数定义,所以隐式强制转换不会发生。 但我不明白为什么编译器不能创建函数定义,然后应用隐式强制转换? 错误是: 在函数“int main()”中: 25:24:错误:调用“test2::add(void(&)(int))”没有匹配函数 25:24:注:候选人是:
根据https://gcc.gnu.org/projects/cxx-status.html,g的第7版,与标志一起使用,支持类模板的模板参数推断。 我希望编译以下代码,特别是因为是一个抽象类: 1。编译器知道不能创建的实例 2。指向base的指针指向一个明确定义的实例(即
我试图在类型s. t上专门化一个类。它忽略了给定类型的恒定性。在这种情况下,该类型是一个模板模板参数: 上面的代码在GCC 4.8.4和clang 5.0(with-std=c 11)中都抱怨bar在与匹配FOFType模板参数化的类一起使用时未定义。即使我删除了sfinae参数,仍然无法找到特化。 这个问题的一个例子可以在这里找到:https://godbolt.org/g/Cjci9C.在上面
我有一个模板类和一个模板返回类型的函数: 假设我想为一个特定类型扩展返回的,并专门为该类型使用函数。因此,让我们创建一个模板来保存返回类型,并在中使用它: 并用它来提供专业化: 然而,gcc和clang都拒绝了最终声明。例如,clang返回: 错误:没有与函数模板专门化“build_wrapped”匹配的函数模板 注意:已忽略候选模板:无法推断模板参数“t” 通过为创建一个明确的专门化,我可以使用