如何引用作为模板参数传递的派生 class 中定义的类型?
How to refer to a type defined in a derived class passed as a template argument?
考虑以下示例:
template <typename T>
class A {
private:
typedef typename T::C C;
};
template <typename T>
class B : public A<B<T>> {
public:
typedef T C;
};
int main() {
B<int> b;
}
用 GCC 编译它会出现以下错误:
test.cc:5:23: error: no type named 'C' in 'B<int>'
typedef typename T::C C;
~~~~~~~~~~~~^
test.cc:9:18: note: in instantiation of template class 'A<B<int> >' requested here
class B : public A<B<T>> {
^
test.cc:15:10: note: in instantiation of template class 'B<int>' requested here
B<int> b;
^
如果定义了 B::C
,为什么编译器会报错?如何解决?
你不能,因为你处于先有鸡还是先有蛋的悖论中。基的定义需要知道派生的定义,这需要基的定义来完成。你只需要想出一个替代方案。一个例子是使用外部元函数将所需的类型传达给任何需要它的人。希望这不在基地成员定义的任何部分,否则你可能就完蛋了。
另一种方法是将 T 作为第二个参数传递。
至此,
class B : public A<B<T>> {
… class B
不完整。 Class A
看不进去
B
中的 C
类型定义可以从 B
中的那一点开始访问,然后继续。它也可以在 B
中的函数体内使用,因为您可以将 class 定义中的函数定义视为 shorthand,以便将其放在 class 之后。但是一个不完整的 class 从外部看什么都不包含:外部代码所能做的就是形成指针和引用,并使用 class 作为模板参数。
template< class C >
using Ungood = typename C::Number;
struct S
{
void foo() { Number x; (void) x; } // OK
Ungood<S> uhuh; //! Nyet.
using Number = double;
};
auto main() -> int {}
您可以通过更改设计来修复您的代码。最明显的是将类型作为单独的模板参数传递。但是,根据您要实现的目标,您当前拥有的继承可能不是真正需要的,甚至没有用。
你不能那样做,因为 this:
A class is considered defined after the closing brace of its class-specifier has been seen [...]
还有一些例外,none 在您的情况下是有效的。
换句话说,当您尝试在基 class 中使用派生 class 来访问类型 C
.
时,您必须将派生 class 视为未完全定义
无论如何,您可以利用派生的 class 是模板 class 这一事实并执行此操作:
template <typename T>
class A;
template <template<typename> class D, typename T>
class A<D<T>> {
private:
using C = T;
};
Aa 你可以看到,我没有给出主模板 class 的定义,因此只能使用模板 classes 的特化。
不确定这是OP的真实情况,但问题中的示例就是这种情况。
考虑以下示例:
template <typename T>
class A {
private:
typedef typename T::C C;
};
template <typename T>
class B : public A<B<T>> {
public:
typedef T C;
};
int main() {
B<int> b;
}
用 GCC 编译它会出现以下错误:
test.cc:5:23: error: no type named 'C' in 'B<int>'
typedef typename T::C C;
~~~~~~~~~~~~^
test.cc:9:18: note: in instantiation of template class 'A<B<int> >' requested here
class B : public A<B<T>> {
^
test.cc:15:10: note: in instantiation of template class 'B<int>' requested here
B<int> b;
^
如果定义了 B::C
,为什么编译器会报错?如何解决?
你不能,因为你处于先有鸡还是先有蛋的悖论中。基的定义需要知道派生的定义,这需要基的定义来完成。你只需要想出一个替代方案。一个例子是使用外部元函数将所需的类型传达给任何需要它的人。希望这不在基地成员定义的任何部分,否则你可能就完蛋了。
另一种方法是将 T 作为第二个参数传递。
至此,
class B : public A<B<T>> {
… class B
不完整。 Class A
看不进去
B
中的 C
类型定义可以从 B
中的那一点开始访问,然后继续。它也可以在 B
中的函数体内使用,因为您可以将 class 定义中的函数定义视为 shorthand,以便将其放在 class 之后。但是一个不完整的 class 从外部看什么都不包含:外部代码所能做的就是形成指针和引用,并使用 class 作为模板参数。
template< class C >
using Ungood = typename C::Number;
struct S
{
void foo() { Number x; (void) x; } // OK
Ungood<S> uhuh; //! Nyet.
using Number = double;
};
auto main() -> int {}
您可以通过更改设计来修复您的代码。最明显的是将类型作为单独的模板参数传递。但是,根据您要实现的目标,您当前拥有的继承可能不是真正需要的,甚至没有用。
你不能那样做,因为 this:
A class is considered defined after the closing brace of its class-specifier has been seen [...]
还有一些例外,none 在您的情况下是有效的。
换句话说,当您尝试在基 class 中使用派生 class 来访问类型 C
.
无论如何,您可以利用派生的 class 是模板 class 这一事实并执行此操作:
template <typename T>
class A;
template <template<typename> class D, typename T>
class A<D<T>> {
private:
using C = T;
};
Aa 你可以看到,我没有给出主模板 class 的定义,因此只能使用模板 classes 的特化。
不确定这是OP的真实情况,但问题中的示例就是这种情况。