Effective C++ 规则44:将与参数无关的代码抽离 Templates

1、与参数无关的代码嵌入模板的危害

模板的主要特点是 泛型化,即为不同的类型参数生成不同的代码。然而,在实际开发中,有些代码逻辑是 与模板参数无关的,但如果这些代码仍然放在模板中,可能会导致以下问题:

  • 代码膨胀(Code Bloat), 模板在编译期间会为每种不同的模板参数生成对应的代码。如果模板中包含大量与参数无关的代码,就会导致不必要的重复代码,从而使编译后的二进制文件体积膨胀。
  • 编译时间变长,模板的实例化需要编译器做额外的工作。如果与参数无关的代码也包含在模板中,会增加编译器的处理负担,导致编译时间显著增加。
  • 可读性降低,模板代码已经足够复杂,如果不必要的逻辑也嵌入模板中,会使代码难以维护和阅读。

2、将与模板参数无关的代码抽离的方法

通过将与模板参数无关的代码从模板中抽离,可以减少模板实例化的冗余,并优化编译性能。

2.1 、将通用代码移动到非模板基类

如果模板类中有部分逻辑与模板参数无关,可以将这部分逻辑提取到一个普通的基类中。然后让模板类继承这个基类,从而避免重复生成与参数无关的代码。没有优化的的模板代码示例:

#include <iostream>

template <typename T>
class MyClass {
public:
    void commonFunction() {
        std::cout << "This is a common function." << std::endl;
    }

    void specificFunction(const T& value) {
        std::cout << "Specific function for: " << value << std::endl;
    }
};

int main() {
    MyClass<int> obj1;
    MyClass<double> obj2;

    obj1.commonFunction(); // 与模板参数无关,但会为每个模板实例重复生成
    obj2.commonFunction();

    obj1.specificFunction(42); // 与模板参数有关
    obj2.specificFunction(3.14);
    return 0;
}

上述代码中,commonFunction 与模板参数无关,但会为每个模板实例重复生成。优化后的代码示例如下:

#include <iostream>

// 非模板基类
class CommonBase {
public:
    void commonFunction() {
        std::cout << "This is a common function." << std::endl;
    }
};

// 模板类继承基类
template <typename T>
class MyClass : public CommonBase {
public:
    void specificFunction(const T& value) {
        std::cout << "Specific function for: " << value << std::endl;
    }
};

int main() {
    MyClass<int> obj1;
    MyClass<double> obj2;

    obj1.commonFunction(); // 使用基类的实现
    obj2.commonFunction();

    obj1.specificFunction(42); // 与模板参数有关
    obj2.specificFunction(3.14);
    return 0;
}

2.2 、将与参数无关的函数实现放在普通函数中

如果模板类中的某些成员函数与模板参数无关,可以将这些函数实现抽离为普通函数,避免在模板实例化时重复生成。未优化的代码如下:

template <typename T>
class Calculator {
public:
    void printHello() {
        std::cout << "Hello, world!" << std::endl;
    }

    T add(const T& a, const T& b) {
        return a + b;
    }
};

优化后的代码:

void printHello() {
   std::cout << "Hello, world!" << std::endl;
}

template <typename T>
class Calculator : public CalculatorBase {
public:
    T add(const T& a, const T& b) {
        return a + b;
    }
};

2.3、使用模板特化优化与参数无关的逻辑

对于某些模板类,如果其中的逻辑完全不依赖模板参数,可以通过模板特化的方式优化代码。

#include <iostream>

// 普通模板
template <typename T>
class Logger {
public:
    void log(const T& message) {
        std::cout << "Log: " << message << std::endl;
    }
};

// 特化版本(与模板参数无关的实现)
template <>
class Logger<void> {
public:
    void log() {
        std::cout << "Log: No message." << std::endl;
    }
};

int main() {
    Logger<int> intLogger;
    intLogger.log(42);

    Logger<void> voidLogger;
    voidLogger.log(); // 使用特化版本
    return 0;
}

通过模板特化,特定情况下的实现可以与模板参数分离,从而优化代码。

3、模板优化的关键点

  • 识别与模板参数无关的代码:找出哪些代码不依赖模板参数,例如通用函数、类型无关的逻辑等。
  • 抽离逻辑,减少重复实例化:将与参数无关的代码抽离到非模板基类或普通函数中。
  • 利用模板特化:针对特定类型或情况,通过模板特化优化代码。
  • 提升编译效率与可读性:减少重复生成的代码,提高编译性能,并使模板代码更易于维护。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值