c++ - 带有子类的模板实例化和特化顺序
问题描述
我试图围绕模板的实例化和专业化的顺序,特别是在涉及子类的情况下。
请考虑以下示例:
class A {
int value() { return 42; }
};
class B {
double value() { return 3.1415; }
};
class MyBase {
public:
virtual int value() = 0;
};
template<class T> class MyClass : public MyBase {
protected:
class Cache;
mutable Cache _cache;
public:
MyClass(T t) : _cache(t.value()) {};
virtual int value() override;
};
template<class T> class MyClass<T>::Cache {
public:
int x;
int getVal(){return x;}
};
template<> class MyClass<B>::Cache {
public:
double z;
int getVal(){return 100*z;}
};
template<class T> int MyClass<T>::value() { return _cache.getVal(); }
typedef MyClass<A> MyA;
typedef MyClass<B> MyB;
这导致error: specialization of ‘MyClass<B>::Cache’ after instantiation
,我不明白。我猜想MyClass<B>::Cache
只有在发生这种情况时才需typedef
要这样做,但似乎并非如此。MyClass
我试图在通用模板定义之前,在定义内部甚至在此之前(使用前向声明)稍微移动一下专业化,但没有任何运气。
有没有合适的方法来实现这样的事情,或者这在逻辑上是不可能的,因为我很高兴能更好地理解这些原因?
我想我可以通过创建一个指针来实现这一点,_cache
这样在定义时不需要完整的定义MyClass
,但我宁愿避免这样做,除非我了解潜在的问题。
解决方案
给读者的其他提醒:
第一个解决方案:
我们专门化整个类,所以我们可以有一个专门化的内部类。现场演示
#include <iostream>
#include <stdexcept>
struct A {
int value() { return 42; }
};
struct B {
double value() { return 3.1415; }
};
class MyBase {
public:
virtual int value() = 0;
};
template <class T> class MyClass : public MyBase {
protected:
struct Cache {
int x;
int getVal() { return x; }
Cache(double v) : x(v){}; // gcc11 need this in c++17, not in c++20
};
public:
mutable Cache _cache;
public:
MyClass(T t) : _cache(t.value()){};
virtual int value() override;
};
template <> class MyClass<B> : public MyBase {
protected:
struct Cache {
double z;
Cache(double v) : z(v){}; // gcc11 need this in c++17, not in c++20
int getVal() { return 100 * z; }
};
mutable Cache _cache;
public:
MyClass(B t) : _cache(t.value()){};
virtual int value() override;
};
template <class T> int MyClass<T>::value() { return _cache.getVal(); }
int MyClass<B>::value() { return _cache.getVal(); }
typedef MyClass<A> MyA;
typedef MyClass<B> MyB;
int main() {
MyA a(A{});
MyB b(B{});
std::cout << a.value() << " " << b.value() << std::endl;
}
第二种解决方案:
制作Cache
模板和外部,MyClass
以便我们可以专业化。恕我直言,它更清洁。现场演示。
#include <iostream>
#include <stdexcept>
struct A {
int value() { return 42; }
};
struct B {
double value() { return 3.1415; }
};
template <class T> struct Cache {
int x;
int getVal() { return x; }
Cache(double v) : x(v){}; // gcc11 need this in c++17, not in c++20
};
template <> struct Cache<B> {
double z;
Cache(double v) : z(v){}; // gcc11 need this in c++17, not in c++20
int getVal() { return 100 * z; }
};
class MyBase {
public:
virtual int value() = 0;
};
template <class T> class MyClass : public MyBase {
protected:
public:
mutable Cache<T> _cache;
public:
MyClass(T t) : _cache(t.value()){};
virtual int value() override;
};
template <class T> int MyClass<T>::value() { return _cache.getVal(); }
typedef MyClass<A> MyA;
typedef MyClass<B> MyB;
int main() {
MyA a(A{});
MyB b(B{});
std::cout << a.value() << " " << b.value() << std::endl;
}
我希望它有所帮助,如果我错过了什么,请告诉我。
推荐阅读
- cucumber - 如何在空手道的同一请求中传递表单数据文本和文件?
- python - 使用 xlsxwriter 创建堆积条形图
- css - 与我的导航栏下拉顺风重叠的元素
- go - 无法导入 Go 包
- java - IntelliJ 高亮错误和警告更加突出
- python - cv2 圆圈不清楚它看起来像菱形
- google-bigquery - BigQuery 存储写入 API 和读取 API 之间的延迟
- php - 将来自不同控制器的多个变量传递到 Laravel 8 中的单个视图
- typescript - 我无法在 React Native 中使用 styled-components 开玩笑
- angularjs - AngularJS 到 Angular12 的迁移(错误:无法解析 AppModule 的所有参数:(?))