如果基类依赖于模板参数,则在非限定名称查找中不会检查其范围。我可以使用
using
声明来引入基类中的名称。假设现在我在基类中有一个类型别名模板。可以使用using
声明将其引入到派生类中吗?
template<class T>
struct Base
{
using Type1 = int;
template<typename S>
using Type2 = S;
};
template<class T>
struct Derived : Base<T>
{
using typename Base<T>::Type1; // Fine
//using Type1 = typename Base<T>::Type1; // Also fine
template<typename S>
using Type2 = typename Base<T>::template Type2<S>;
};
Type2
的行可以替换为与 Type1
的(未注释的)行类似的内容吗?
template<class T>
struct Derived : Base<T>
{
using Base<T>::Type2;
void foo() {
// Using the Type2 alias template
// inside our class to declare a local variable.
typename Derived::template Type2<int> i;
}
};
// Using the Type2 alias template
// outside the class to declare another type.
using X = Derived<int>::Type2<int>;
这是正确的语法,所有支持 C++11 的编译器都应该允许这样做。 请参阅此处的现场演示。
我的意思是这样简单的东西:
,可能带有using Base<T>::Type2;
s 和typename
s。template
我们在
using
声明中不需要这些消歧符,但是当我们想在Type2
中使用Derived
时,我们仍然需要:
template
消歧器,因为 Type2
是一个模板,而 Derived
依赖于 T
typename
消歧符指定Type2<...>
是一种类型另请参阅:cpp 有关从属名称的参考文章
这种语法解决的问题是,用作基本类型的潜在类型
Base<T>
可以在此定义之后但在 Derived
实例化之前进行专门化。
大多数时候,只要
Type2
是模板,这种语法就可以工作。这里可能的 XY 问题是您尝试获得更通用的语法。可悲的是,这是不可能的。解决方案只是将类型定义与 Derived
类分开。
在C++中,我们可以使用
using typename Base<T>::Type1
从基类Type1
引入类型名称Base<T>
。使用 using typename Base<T>::template Type2
扩展此语法以引入模板名称 Type2
似乎很直观。但是,当前的 C++ 标准不支持此扩展。该提案可追溯到 1999 年,如 CWG109 中所述。
不合并此 using template 语法的一个原因是 C++11 中引入的 alias templates 的存在。正如您所提到的,别名模板提供了类似的功能,并且被认为是对使用模板的改进,尽管后者可能提供更简单的语法。引入使用模板的含义将能够创建模板模板:
template<typename S>
using Type2 = typename Base<T>::template Type2;
我们如何实例化这个别名模板,它为每个未使用的类型参数
S
引入了一个模板?也许Type2<int><int>
可以工作?然而,有人可能会反对这种用法。尽管我们可以通过措辞进行限制,但这种努力可能并不能证明结果的合理性。正如委员会的结论:
此时没有足够的动力进行改变。
那么,我们的选择是什么?考虑像下面这样的宏,它可能提供一种解决方法(demo):
#define USING_TEMPLATE(B, T) \
template <class UTType> using T = typename B::template T<UTType>
// Example:
template <class T> struct B {
template <class U> using Type = U;
};
template <class T> struct D : B<T> {
USING_TEMPLATE(B<T>, Type);
// The above macro expands to:
// template <class UTType>
// using Type = typename B<T>::template Type<UTType>;
D() { (void)Type<int>(42); }
};