当在模板中使用 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
没有语义意义, - 7.3.3/5 已经明确禁止的允许
:: template-id
,以及 - 允许
template
已经有足够规格的关键字来修补漏洞。
这个分析正确吗?
考虑到新语法是允许的,也许一个声明typename
应该导入一个类模板或别名模板,而一个不typename
应该导入一个函数或变量模板到当前作用域。
using typename derived::base::template ct;
using derived::base::ft;
这可能需要一些额外的规范。此外,目前的现状似乎是依赖的模板名称总是有模棱两可的种类(不是模板ID),所以根本不清楚它是否typename
属于ct
。