C++ 找不到在继承自当前模板 class 的模板基 class 中定义的类型
C++ cannot find type defined in template base class which inherits from the current template class
我正在尝试编写 template class defining a super
type idiom 的变体。 class Inherit
引入类型 Super
来表示可能很长的超类型,并且还需要知道派生类型 New
来做一些额外的事情,我此处未显示。
如果传递给 New
的类型不是模板,则此方法工作正常,但模板失败。这是一个用 clang++-3.8 -std=c++1y -Wall
编译的完整示例(gcc 给出相同的输出):
struct SomeBase {};
template<class New, class Base>
struct Inherit : Base {
using Super = Inherit<New, Base>;
};
struct NonTemplate : Inherit<NonTemplate, SomeBase> {
using X = Super;
// compiles and is nice and short
};
template<class T>
struct Template : Inherit<Template<T>, SomeBase>
{
using A = Super;
// error: unknown type name 'Super'; did you mean 'NonTemplate::Super'?
using B = typename Super;
// error: expected a qualified name after 'typename'
using C = Inherit::Super;
// error: 'Inherit' is not a class, namespace, or enumeration
using D = typename Inherit<Template<T>, SomeBase>::Super;
// compiles, but what's the point?
};
int main() {
return 0;
}
如果我不需要 New
参数,我也可以将 Inherit
与模板一起使用,但我确实需要 New
。我可以使用选项 D
编译代码,但这违背了整个目的。
我有两个问题:
- 阻止类型名称的语言问题到底是什么
Super
在 class Template
中为人所知,为什么在 NonTemplate
中有所不同?
- 有没有人有解决这个问题的好办法?
问题是 Inherit<Template<T>, SomeBase>
是一个 依赖基础 class,即 class 依赖于模板参数。从属基础 class 中的名称在不合格的查找中隐藏,因此您需要限定名称。
typename
是必需的,因为 Inherit<Template<T>, SomeBase>::Super
是一个依赖名称,编译器需要你告诉它它命名一个类型,因为它只能在实例化时确定。
有关 typename
关键字的深入解释,请参阅 Where and why do I have to put the “template” and “typename” keywords?。
至于解决方案,您可以将 Super
分解为类型特征:
template<class New, class Base>
struct Inherit : Base {
};
namespace detail {
template <class New, class Base>
Inherit<New,Base> Super (const Inherit<New, Base>&);
}
template <class T>
using Super = decltype(detail::Super(std::declval<T>()));
这使使用变得更加简单:
template<class T>
struct Template : Inherit<Template<T>, SomeBase>
{
using D = Super<Template>;
};
如果您发现自己需要这个用于多个基 classes,您可以将其概括:
namespace detail {
template <template <typename...> class T, class... Args>
T<Args...> Super (const T<Args...>&);
}
template <template <typename...> class Base, class Derived>
using Super = decltype(detail::Super<Base>(std::declval<Derived>()));
template <typename T>
using InheritSuper = Super<Inherit,T>;
template<class T>
struct Template : Inherit<Template<T>, SomeBase>
{
using D = InheritSuper<Template>;
};
我正在尝试编写 template class defining a super
type idiom 的变体。 class Inherit
引入类型 Super
来表示可能很长的超类型,并且还需要知道派生类型 New
来做一些额外的事情,我此处未显示。
如果传递给 New
的类型不是模板,则此方法工作正常,但模板失败。这是一个用 clang++-3.8 -std=c++1y -Wall
编译的完整示例(gcc 给出相同的输出):
struct SomeBase {};
template<class New, class Base>
struct Inherit : Base {
using Super = Inherit<New, Base>;
};
struct NonTemplate : Inherit<NonTemplate, SomeBase> {
using X = Super;
// compiles and is nice and short
};
template<class T>
struct Template : Inherit<Template<T>, SomeBase>
{
using A = Super;
// error: unknown type name 'Super'; did you mean 'NonTemplate::Super'?
using B = typename Super;
// error: expected a qualified name after 'typename'
using C = Inherit::Super;
// error: 'Inherit' is not a class, namespace, or enumeration
using D = typename Inherit<Template<T>, SomeBase>::Super;
// compiles, but what's the point?
};
int main() {
return 0;
}
如果我不需要 New
参数,我也可以将 Inherit
与模板一起使用,但我确实需要 New
。我可以使用选项 D
编译代码,但这违背了整个目的。
我有两个问题:
- 阻止类型名称的语言问题到底是什么
Super
在 classTemplate
中为人所知,为什么在NonTemplate
中有所不同? - 有没有人有解决这个问题的好办法?
问题是 Inherit<Template<T>, SomeBase>
是一个 依赖基础 class,即 class 依赖于模板参数。从属基础 class 中的名称在不合格的查找中隐藏,因此您需要限定名称。
typename
是必需的,因为 Inherit<Template<T>, SomeBase>::Super
是一个依赖名称,编译器需要你告诉它它命名一个类型,因为它只能在实例化时确定。
有关 typename
关键字的深入解释,请参阅 Where and why do I have to put the “template” and “typename” keywords?。
至于解决方案,您可以将 Super
分解为类型特征:
template<class New, class Base>
struct Inherit : Base {
};
namespace detail {
template <class New, class Base>
Inherit<New,Base> Super (const Inherit<New, Base>&);
}
template <class T>
using Super = decltype(detail::Super(std::declval<T>()));
这使使用变得更加简单:
template<class T>
struct Template : Inherit<Template<T>, SomeBase>
{
using D = Super<Template>;
};
如果您发现自己需要这个用于多个基 classes,您可以将其概括:
namespace detail {
template <template <typename...> class T, class... Args>
T<Args...> Super (const T<Args...>&);
}
template <template <typename...> class Base, class Derived>
using Super = decltype(detail::Super<Base>(std::declval<Derived>()));
template <typename T>
using InheritSuper = Super<Inherit,T>;
template<class T>
struct Template : Inherit<Template<T>, SomeBase>
{
using D = InheritSuper<Template>;
};