在思考如何在 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/

10-11 22:54
查看更多