【问题标题】:Using declaration for type-dependent template name使用依赖于类型的模板名称的声明
【发布时间】:2013-03-03 15:05:51
【问题描述】:

当在模板中使用 CRTP 时(或者通常当模板参数作为基类模板参数传递时),是否无法在 using 声明中命名基类的成员模板?

template< typename d >
struct base {
    template< typename >
    struct ct {};

    template< typename >
    void ft() {}
};

template< typename x >
struct derived : base< derived< x > > {
     using derived::base::template ct; // doesn't work
     using derived::base::ft; // works but can't be used in a template-id
};

在我看来,这是语言中的一个漏洞,仅仅是因为 using-declaration 语法产生式没有包含 qualified-id

using-declaration:
    using typename(opt) nested-name-specifier unqualified-id ; // have this
    using :: unqualified-id ;

unqualified-id:
    identifier
    operator-function-id
    conversion-function-id
    literal-operator-id
    ~ class-name
    ~ decltype-specifier
    template-id

qualified-id:
    nested-name-specifier template(opt) unqualified-id // want this
    :: identifier
    :: operator-function-id
    :: literal-operator-id
    :: template-id

如果唯一的规则是using-declaration: using typename(opt) qualified-id,那么唯一的结果就是

  • 排除没有语义意义的:: conversion-function-id:: ~ class-name:: ~ decltype-specifier template-id
  • 允许 :: template-id 已被 7.3.3/5 明确禁止,并且
  • 允许template 关键字已经有足够的规范来修补漏洞。

这个分析正确吗?

鉴于允许使用新语法,也许带有typename 的声明应该导入类模板或别名模板,而没有typename 的声明应该将函数或变量模板导入当前作用域。

     using typename derived::base::template ct;
     using derived::base::ft;

这可能需要一些额外的规范。此外,目前的现状似乎是依赖的模板名称总是有模棱两可的类型(不是模板 ID),所以根本不清楚 typename 是否属于 ct

【问题讨论】:

  • 一个有趣的分析。我很好奇你会在哪里使用这个被识别的“洞”会被抑制的方式。 IE。什么是现实世界的应用程序,这是导致您不得不退后一步并重新考虑程序架构的障碍?
  • @WhozCraig 每当您使用模板中的 CRTP 时都会出现这种情况。基类提供了一个接口,你必须在每次使用时说this-&gt;*templatebase::template
  • 好的,我想我明白了。这种特殊情况是关于将其与using 子句一起使用以使生活更轻松,但似乎不允许这样做。好的例子。谢谢。
  • 不确定问题到底是什么......您是在询问语言还是在询问语言的假设更改是否有意义/正确/解决您的问题?
  • @DavidRodríguez-dribeas 两者。如果我对语言有误,那么我在如何修复它方面肯定是错的。我有点希望我对语言的理解是错误的,但现在这似乎是一个渺茫的机会。也许在这一点上,我应该继续询问这应该是 DR 还是提案文件……

标签: c++ templates grammar crtp


【解决方案1】:

以下内容适用于 C++11:

#include <iostream>

template< typename d >
struct base {
    template< typename >
    struct ct {};

    template< typename >
    void ft() {std::cerr << "cheesecake" << std::endl;}
};

template< typename x >
struct derived : base< derived< x > > {
  template<typename X>
    using ct = typename derived::base::template ct<X>; // new in C++11
  using derived::base::ft;
};

int main()
{
  derived<int>::ct<float> c;
  derived<int> a;
  a.ft<int>();
}

如果这不是您想要的,您能否举例说明您希望如何使用 ctft

【讨论】:

  • 是的,模板别名有效,尽管它需要重新声明模板签名,这在某种程度上打破了关注点的分离。函数using 声明在derived 范围内不起作用。完美的转发将起作用。但这些没有使用声明。添加的步法违背了using 声明的目的,即将声明从一个范围导入到相关范围 没有声明新内容。无论如何......添加完美的转发,我应该接受这个。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-08
  • 2011-01-04
  • 1970-01-01
  • 2016-01-06
  • 1970-01-01
相关资源
最近更新 更多