为C++中模板的所有实例生成的单个机器代码实例:它是否可行和/或可能
Single machine code instance generated for all instances of a template in C++: Is it feasible and/or possible?
我一直在思考这个问题,我想我在的某个地方读到了它,但我再也找不到更多关于它的信息了。
仅出于理论而非实践目的,生成一个能够处理此类模板的所有实例的模板实例是否可能、可行和/或实用?有编译器能够做到这一点吗?
例如,考虑这个类模板。。。
template<typename T>
class UselessCalculator {
private:
T result;
public:
UselessCalculator() : result(0) {}
UselessCalculator &operator=(T what) {
this->result = what;
return *this;
}
UselessCalculator &operator+=(T what) {
this->result += what;
return *this;
}
UselessCalculator &operator-=(T what) {
this->result -= what;
return *this;
}
UselessCalculator &operator*=(T what) {
this->result *= what;
return *this;
}
UselessCalculator &operator/=(T what) {
this->result /= what;
return *this;
}
};
对于任何T
,UselessCalculator
都有一个需求列表,可以用作它的模板参数,就像概念一样。在这种情况下,要求是:
- 可通过CCD_ 3进行初始化
operator+=(T, T)
过载operator-=(T, T)
过载operator*=(T, T)
过载operator/=(T, T)
过载
现在,根据这个愚蠢的"单一实例适用于所有"的想法,这将如何实现?我认为下面的C代码可以说明一种可能性。。。
struct UselessCalculatorTemplateVirtualTable {
struct someFunkyImplementationOfStdTypeInfo *type;
void (*constructInt)(void*, int);
void (*copyConstruct)(void*, const void*);
void (*moveConstruct)(void*, void*);
void (*destruct)(void*);
void (*operatorAddAssign)(void*, const void*);
void (*operatorSubtractAssign)(void*, const void*);
void (*operatorMultiplyAssign)(void*, const void*);
void (*operatorDivideAssign)(void*, const void*);
};
// I won't repeat that long name all over the place...
typedef struct UselessCalculatorTemplateVirtualTable VirtualTable;
void UselessCalculatorConstruct(VirtualTable *table, void *this) {
table->constructInt(this, 0);
}
void UselessCalculatorCopy(VirtualTable *table, void *this, const void *what) {
table->copyConstruct(this, what);
}
void UselessCalculatorMove(VirtualTable *table, void *this, void *what) {
table->moveConstruct(this, what);
}
void UselessCalculatorDestruct(VirtualTable *table, void *this) {
table->destruct(this);
}
void UselessCalculatorAddAssign(VirtualTable *table, void *this, void *what) {
table->operatorAddAssign(this, what);
}
void UselessCalculatorAddAssign(VirtualTable *table, void *this, void *what) {
table->operatorSubtractAssign(this, what);
}
void UselessCalculatorMultiplyAssign(VirtualTable *table, void *this, void *what) {
table->operatorMultiplyAssign(this, what);
}
void UselessCalculatorDivideAssign(VirtualTable *table, void *this, void *what) {
table->operatorDivideAssign(this, what);
}
现在,编译器必须为每个UselessCalculator<T>
"实例化"的唯一东西就是VirtualTable
和辅助函数(如果有的话)。例如,UselessCalculator<int>
将翻译为…
#define real(what) ((int*)what)
void constructInt(void *this, int what) {
*real(this) = what;
}
void copyConstruct(void *this, const void *what) {
*real(this) = *real(what);
}
void moveConstruct(void *this, void *what) {
*real(this) = *real(what);
}
void destruct(void *this) {}
void operatorAddAssign(void *this, const void *what) {
*real(this) += *real(what);
}
void operatorSubtractAssign(void *this, const void *what) {
*real(this) -= *real(what);
}
void operatorMultiplyAssign(void *this, const void *what) {
*real(this) *= *real(what);
}
void operatorDivideAssign(void *this, const void *what) {
*real(this) /= *real(what);
}
那么,考虑到这一点。。。
int main() {
UselessCalculator<int> myUselessCalc;
myUselessCalc += 10;
myUselessCalc *= 10;
myUselessCalc -= 10;
myUselessCalc /= 10;
}
VirtualTable virtualTableInt = {
&someFunkyImplementationOfStdTypeInfoForInt,
constructInt,
copyConstruct,
moveConstruct,
destroy,
addAssign,
subtractAssign,
multiplyAssign,
divideAssign
};
可以翻译成这个C代码。。。(不考虑例外情况!)
struct UselessCalculatorInt {
int result;
};
int main() {
int tmpStorage;
UselessCalculatorInt myUselessCalc;
UselessCalculatorConstruct(&virtualTableInt, &myUselessCalc);
tmpStorage = 10;
UselessCalculatorAddAssign(&virtualTableInt, &myUselessCalc, &tmpStorage);
tmpStorage = 10;
UselessCalculatorSubtractAssign(&virtualTableInt, &myUselessCalc, &tmpStorage);
tmpStorage = 10;
UselessCalculatorMultiplyAssign(&virtualTableInt, &myUselessCalc, &tmpStorage);
tmpStorage = 10;
UselessCalculatorDivideAssign(&virtualTableInt, &myUselessCalc, &tmpStorage);
UselessCalculatorDestroy(&virtualTableInt, &myUselessCalc);
return 0;
}
我知道这会违背模板的所有目的,很多人不会喜欢这个想法(我不喜欢,我只是好奇),而且代码的CPU和内存效率可能会降低,更不用说它几乎是不可优化的,它们不再是"模板"了。但其他人ab过去使用得更糟,不是吗?;)BTW,如果有必要,最好有一个开关来禁用它,因为模板元编程几乎毫无用处。
所以,我的问题是,如果还不够清楚的话,所有这些混乱是否可行、实用、可实施?某个工具链是否成功地做到了这一点?它能提供任何超过其明显管理费用的好处吗?
好吧,你基本上是在问一些编译器是否可以通过运行时多态性(具有虚拟函数的"经典"OOP)来实现所谓的"编译时多态性"(C++模板)。
虽然这在理论上是可能的(至少在一定程度上),但如果真的违背了语言设计原则。在编译时多态性更合适的环境中,模板是专门作为运行时多态性的有效替代品提供的。模板的全部目的是不同于"普通"的运行时多态性。许多模板特性在很大程度上取决于它们的编译时特性。
其思想是,如果您使用模板,这意味着您想要编译时多态性,而不是运行时多态性。
这是奖牌的一面。另一方面,写得不好的模板代码可能会导致不必要的代码膨胀,因为在运行时多态性本可以用更少的代码膨胀和可忽略的性能损失轻松实现相同目的的情况下,会强制编译时多态性(即同一代码的重复实例化)。从这个角度来看,在模板代码中隐式自动切换到运行时多态性可能是有益的。但我相信,目前的语言并不是为这一点量身定制的。这是你应该明确自己做的事情。
- 在C++中,是否可以基于给定的标识符创建基类的新实例,反之亦然
- 检查某些类型是否是模板类 std::optional 的实例化
- 如何检查类实例向量的索引是否为空
- 检查类是否在方法中实例化
- 实例化模板时,我是否必须显式显示参数包中的类型?
- <Base> <Derived> 具有相同原始指针共享引用的 shared_ptr 和 shared_ptr 实例是否计数?
- 是否可以检查给定exception_ptr实例是否拥有某种类型的异常?
- 使用模板检查我的类的两个实例是否相等
- 将新放置到缓冲区后,缓冲区和实例是否具有相同的 void* 地址?
- 创建 QQuickItem 子类的实例是否有问题,我不打算渲染或添加到 QML 树中的实例?
- 实例是否应该使用资源库/获取器来访问自己的私有数据成员
- C++模板能否确定所声明/定义的实例是否为常量
- 类的实例是否仍在同一进程内的线程之间共享相同的静态成员
- 如何从成员函数中检测实例是否为常量
- 检查实例是否存在,并在Singleton getInstance();中返回引用;
- 如何检查我的类的两个实例是否相等
- 检查程序的另一个实例是否已经运行
- 释放类的实例是否也会释放由其对象/方法动态分配的内存?
- 如何测试实例是否已损坏
- 我想检查类实例是否已经存储在std::vector中