我曾多次在类似
的课程上跌跌撞撞class PureVirtualClass
{
virtual int foo() = 0;
virtual bool bar() = 0;
}
template <class T> class ImplClass : public virtual PureVirtualClass
{
virtual ~ImplClass(){};
int foo() { return 42;}
bool bar() { return true;}
//several other method having nothing to do with T
}
这个&#34;设计&#34;经常出现我想通过将ImplClass
定义为模板类但没有任何引用到模板参数T
任何地方< / em>的。我自己的c ++模板知识有点受限。
这有什么好处,还是只是一个混乱的程序员?
答案 0 :(得分:3)
可以对模板化的类有益,但不依赖于参数。大多数情况下,你会看到为模板元编程定义(空)标签结构的事情:
template <class X>
struct some_tag {};
像你这样的类的好处一般是,虽然你在每个类中具有相同的功能,但它们是不同的类,你不能将一个复制到另一个类,即ImplClass<int>
类型的对象与ImplCalss<float>
类型的另一个对象不兼容。
答案 1 :(得分:3)
Arne提到的这个想法有很多有用的案例。例如,查看Very basic tuple implementation,这就是如何定义单个元组元素:
template <size_t N, typename T>
class TupleElem
{
T elem;
public:
T& get() { return elem; }
const T& get() const { return elem; }
};
它是N
的模板,不依赖于它。为什么?因为元组实现
template <size_t... N, typename... T>
class TupleImpl <sizes <N...>, T...> : TupleElem <N, T>...
{
//..
};
派生多个此类元素,每个元素都有一个唯一的N
,用作标识符。没有它,TupleImpl
将两次派生相同的类,在参数包T...
中有两个元素类型相同。在这种情况下,random access元素都不会起作用(通过显式调用适当的get()
基类的函数TupleElem
,这将是不明确的),也不是empty base optimization(通过专门针对空类型TupleElem
的{{1}}到而非的T
数据成员{。}}。
这是一个真实的用例,以及clang实现T
的确切方式。当然,像std::tuple
这样的类将是隐藏的实现细节,而不是接口的一部分。例如,gcc遵循完全不同的递归类设计。
通常,您需要学习 context ,其中使用类来理解设计者的意图。
答案 2 :(得分:1)
也许开发人员懒得将类拆分成.h和.cpp文件?
如果在多个编译单元中使用类,则不使用模板会发生链接器错误。使用模板时,链接器通常会在链接时丢弃模板的重复实例化(或以不同方式处理问题)。
虽然这可能是“为什么开发人员这样做”的答案,但如果问题是“何时应该引入从未使用的模板参数”,我不建议这样做(请参阅其他答案)。即使将代码拆分为.h和.cpp(特别是在用于Java或C#等语言时)也很烦人,但这是通常的C ++方式。与仅为此目的使用模板相比,它更容易阅读/理解。此外,它使类的使用更不易读。