为C++中模板的所有实例生成的单个机器代码实例:它是否可行和/或可能

Single machine code instance generated for all instances of a template in C++: Is it feasible and/or possible?

本文关键字:实例 是否 代码 单个 C++ 机器      更新时间:2023-10-16

我一直在思考这个问题,我想我在的某个地方读到了它,但我再也找不到更多关于它的信息了。

仅出于理论而非实践目的,生成一个能够处理此类模板的所有实例的模板实例是否可能、可行和/或实用?有编译器能够做到这一点吗?

例如,考虑这个类模板。。。

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;
        }
};

对于任何TUselessCalculator都有一个需求列表,可以用作它的模板参数,就像概念一样。在这种情况下,要求是:

  • 可通过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++模板)。

虽然这在理论上是可能的(至少在一定程度上),但如果真的违背了语言设计原则。在编译时多态性更合适的环境中,模板是专门作为运行时多态性的有效替代品提供的。模板的全部目的是不同于"普通"的运行时多态性。许多模板特性在很大程度上取决于它们的编译时特性。

其思想是,如果您使用模板,这意味着您想要编译时多态性,而不是运行时多态性。

这是奖牌的一面。另一方面,写得不好的模板代码可能会导致不必要的代码膨胀,因为在运行时多态性本可以用更少的代码膨胀和可忽略的性能损失轻松实现相同目的的情况下,会强制编译时多态性(即同一代码的重复实例化)。从这个角度来看,在模板代码中隐式自动切换到运行时多态性可能是有益的。但我相信,目前的语言并不是为这一点量身定制的。这是你应该明确自己做的事情。