模板别名和相关名称 [英] Template aliases and dependent names
问题描述
在考虑如何在 C ++ 11 中改进 CRTP 的同时,我以以下代码结尾:
While thinking how CRTP can be improved in C++11, I ended with the following code:
template <typename Derived, typename Delayer>
struct derived_value_type
{
typedef typename Derived::value_type type;
};
template <typename Derived>
struct base
{
template <typename Delayer = void>
typename derived_value_type<Derived, Delayer>::type
foo(){ return {}; }
};
struct derived : base<derived>
{
typedef int value_type;
};
#include <iostream>
#include <typeinfo>
int main()
{
derived d;
auto bar = d.foo();
std::cout << typeid(bar).name() << ':' << bar << std::endl;
}
我相信先前的代码符合标准,并且可以编译并与主要的编译器一起使用(导致i:0
).但是,当我使用模板别名代替时,由于derived
不完整而导致编译错误:
I believe the previous code to be standard conformant, and it compiles and works with the major compilers (resulting in i:0
). However, when I use a template alias instead, I get a compilation error due to derived
being incomplete:
template <typename Derived, typename Delayer>
using derived_value_type = typename Derived::value_type;
/*...*/
template <typename Delayer = void>
derived_value_type<Derived, Delayer>
foo(){ return {}; }
这是编译器错误,还是编译器可以确定Delayer
没有真正的依赖关系这一事实是否意味着模板别名不是依赖类型?在标准中在哪里指定?
Is this a compiler bug, or does the fact that the compiler can determinate that there is no real dependency with Delayer
mean that the template alias is not a dependent type? Where is this specified in the standard?
推荐答案
实例化了类模板和函数模板,但仅替换了别名模板.而且,通过删除成员名称type
,您将失去调用依赖名称查找规则的机会.
Class templates and function templates are instantiated, but alias templates are simply substituted. And by getting rid of the member name type
, you lose a chance at invoking the dependent name lookup rules.
[N3285] 14.5.7p2:
[N3285] 14.5.7p2:
当 template-id 指代别名模板的特殊化时,它等同于通过将其 template-arguments 替换为而获得的关联类型.别名模板的 type-id 中的> template-parameters .
When a template-id refers to the specialization of an alias template, it is equivalent to the associated type obtained by substitution of its template-arguments for the template-parameters in the type-id of the alias template.
因此,在第一种情况下,您具有:
So in the first case, you have:
struct derived
的定义要求base<derived>
的隐式实例化.在此实例化期间,我们发现base<derived>
具有成员函数模板:
The definition of struct derived
requires the implicit instantiation of base<derived>
. During this instantiation, we discover base<derived>
has a member function template:
template <typename Delayer=void>
typename derived_value_type<derived, Delayer>::type foo();
返回类型是依赖的,因此尚未查找type
,并且没有实例化derived_value_type
的特殊化.实例化完成,并且base<derived>
和derived
现在都是完整的类型.
The return type is dependent, so type
is not yet looked up, and no specialization of derived_value_type
is instantiated. The instantiation finishes, and base<derived>
and derived
are both now complete types.
在main
中,表达式d.foo()
需要base<derived>::foo<void>()
的隐式实例化.现在查找名称typename derived_value_type<derived, void>::type
,并沿途实例化derived_value_type<derived, void>
.返回类型为int
.
In main
, the expression d.foo()
requires the implicit instantiation of base<derived>::foo<void>()
. Now the name typename derived_value_type<derived, void>::type
is looked up, instantiating derived_value_type<derived, void>
along the way. The return type is found to be int
.
在第二种情况下,derived_value_type
不是从属名称,因此绑定到模板base<D>
定义中的别名模板声明.编译器可以在模板定义时或在类的每个实例化期间进行别名替换,但是可以通过两种方式获得等效于以下内容的类模板:
In the second case, derived_value_type
is not a dependent name, so is bound to your alias template declaration at the definition of template base<D>
. The compiler could do the alias substitution either at the template definition or during each instantiation of the class, but either way you get a class template equivalent to:
template <typename Derived>
struct base
{
template <typename Delayer = void>
typename Derived::value_type
foo(){ return {}; }
};
struct derived
的定义要求base<derived>
的隐式实例化.在此实例化期间,我们发现base<derived>
具有成员函数模板:
The definition of struct derived
requires the implicit instantiation of base<derived>
. During this instantiation, we discover base<derived>
has a member function template:
template <typename Delayer=void>
typename derived::value_type foo();
但是derived::value_type
不依赖,并且derived
是不完整的类型,因此代码格式错误.
But derived::value_type
is not dependent, and derived
is an incomplete type, so the code is ill-formed.
这篇关于模板别名和相关名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!