在思考如何在 C++ 11 中改善CRTP时,我以以下代码结束:
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
不完整,我收到了编译错误: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
没有真正的依赖关系这一事实是否意味着模板别名不是依赖类型?该标准在哪里规定? 最佳答案
类模板和函数模板被实例化,但是别名模板被简单地替换。并且通过删除成员名称type
,您将失去调用依赖名称查找规则的机会。
[N3285] 14.5.7p2:
因此,在第一种情况下,您具有:struct derived
的定义需要base<derived>
的隐式实例化。在此实例化期间,我们发现base<derived>
具有成员函数模板:
template <typename Delayer=void>
typename derived_value_type<derived, Delayer>::type foo();
返回类型是依赖的,因此尚未查找
type
,并且没有实例化derived_value_type
的特殊化。实例化完成,并且base<derived>
和derived
现在都是完整的类型。在
main
中,表达式d.foo()
需要base<derived>::foo<void>()
的隐式实例化。现在,查找名称typename derived_value_type<derived, void>::type
,并在此过程中实例化derived_value_type<derived, void>
。返回类型为int
。在第二种情况下,
derived_value_type
不是从属名称,因此在模板base<D>
的定义中绑定(bind)到您的别名模板声明。编译器可以在模板定义时或在类的每个实例化期间进行别名替换,但是可以通过两种方式获得等效于以下内容的类模板:template <typename Derived>
struct base
{
template <typename Delayer = void>
typename Derived::value_type
foo(){ return {}; }
};
struct derived
的定义需要base<derived>
的隐式实例化。在此实例化期间,我们发现base<derived>
具有成员函数模板:template <typename Delayer=void>
typename derived::value_type foo();
但是
derived::value_type
不依赖,并且derived
是不完整的类型,因此代码格式错误。关于c++ - 模板别名和相关名称,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21395786/