【问题标题】:Template aliases and dependent names模板别名和依赖名称
【发布时间】:2014-01-28 02:33:49
【问题描述】:

在考虑如何在 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 没有真正的依赖关系这一事实是否意味着模板别名不是依赖类型?这在标准中的什么地方规定?

【问题讨论】:

    标签: c++ templates c++11 language-lawyer


    【解决方案1】:

    类模板和函数模板被实例化,但别名模板被简单地替换。并且通过删除成员名称type,您将失去调用从属名称查找规则的机会。

    [N3285]14.5.7p2:

    当一个template-id指代一个别名模板的特化时,它等价于用它的template-arguments代替得到的关联类型>template-parameters 在别名模板的 type-id 中。

    所以在第一种情况下,你有:

    struct derived 的定义需要 base&lt;derived&gt; 的隐式实例化。在这个实例化过程中,我们发现base&lt;derived&gt; 有一个成员函数模板:

    template <typename Delayer=void>
    typename derived_value_type<derived, Delayer>::type foo();
    

    返回类型是依赖的,所以type 还没有被查找,derived_value_type 的特化没有被实例化。实例化完成,base&lt;derived&gt; 和 derived 现在都是完整类型。

    在main 中,表达式d.foo() 需要隐式实例化base&lt;derived&gt;::foo&lt;void&gt;()。现在查找名称typename derived_value_type&lt;derived, void&gt;::type,沿途实例化derived_value_type&lt;derived, void&gt;。发现返回类型为int。

    在第二种情况下,derived_value_type 不是从属名称,因此在模板 base&lt;D&gt; 的定义处绑定到您的别名模板声明。编译器可以在模板定义或类的每次实例化期间进行别名替换,但无论哪种方式,您都会得到一个等效于的类模板:

    template <typename Derived>
    struct base
    {
      template <typename Delayer = void>
      typename Derived::value_type
      foo(){ return {}; }
    };
    

    struct derived 的定义需要 base&lt;derived&gt; 的隐式实例化。在这个实例化过程中,我们发现base&lt;derived&gt; 有一个成员函数模板:

    template <typename Delayer=void>
    typename derived::value_type foo();
    

    但是derived::value_type是不依赖的,derived是不完整的类型,所以代码格式不正确。

    【讨论】:

      猜你喜欢
      • 2018-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-26
      • 1970-01-01
      • 1970-01-01
      • 2013-03-03
      相关资源
      最近更新 更多