MST

星途 面试题库

面试题:C++ #if!defined 宏定义在模板元编程中的深度应用

在 C++ 的模板元编程场景下,#if!defined 宏定义也能发挥独特作用。假设你正在开发一个通用的模板库,需要根据不同的编译期条件选择不同的模板实例化。利用 #if!defined 宏定义结合模板元编程技术,设计一个模板类,该类能在编译期根据某个自定义的编译期常量(例如一个代表数据类型大小的常量)选择不同的内部数据存储结构(例如当数据类型大小小于等于 4 字节时使用 std::vector<char>,大于 4 字节时使用 std::vector<int>),并详细解释代码的工作原理以及在这种场景下使用 #if!defined 宏定义相较于其他编译期选择机制的优势和劣势。
27.8万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

代码实现

#include <iostream>
#include <vector>

// 自定义编译期常量,代表数据类型大小
#define DATA_TYPE_SIZE 8

// 根据DATA_TYPE_SIZE选择不同的内部数据存储结构
#if!defined(DATA_TYPE_SIZE) || DATA_TYPE_SIZE <= 4
using storage_type = std::vector<char>;
#else
using storage_type = std::vector<int>;
#endif

template <typename T>
class CustomTemplate {
private:
    storage_type data;

public:
    CustomTemplate() = default;

    void addElement(T element) {
        // 根据storage_type的实际类型添加元素
        if constexpr (std::is_same_v<storage_type, std::vector<char>>) {
            data.resize(data.size() + sizeof(T));
            char* ptr = data.data() + data.size() - sizeof(T);
            new (ptr) T(element);
        } else if constexpr (std::is_same_v<storage_type, std::vector<int>>) {
            data.push_back(*reinterpret_cast<int*>(&element));
        }
    }

    void printData() {
        if constexpr (std::is_same_v<storage_type, std::vector<char>>) {
            for (size_t i = 0; i < data.size(); i += sizeof(T)) {
                T value;
                std::memcpy(&value, data.data() + i, sizeof(T));
                std::cout << value << " ";
            }
        } else if constexpr (std::is_same_v<storage_type, std::vector<int>>) {
            for (int val : data) {
                std::cout << val << " ";
            }
        }
        std::cout << std::endl;
    }
};

代码工作原理

  1. 宏定义判断:通过#if!defined(DATA_TYPE_SIZE) || DATA_TYPE_SIZE <= 4判断自定义编译期常量DATA_TYPE_SIZE是否定义以及其值是否小于等于4。如果满足条件,则storage_type定义为std::vector<char>;否则定义为std::vector<int>
  2. 模板类定义CustomTemplate模板类内部使用storage_type作为数据存储结构。addElement成员函数根据storage_type的实际类型来添加元素,printData成员函数根据storage_type的实际类型来打印数据。

#if!defined宏定义的优势

  1. 简单直观:宏定义的语法简单,对于根据简单编译期常量进行条件选择的场景,代码逻辑一目了然。
  2. 与编译环境紧密结合:可以直接利用编译器的预处理功能,在编译早期就完成条件判断,不依赖于运行时的任何逻辑。

#if!defined宏定义的劣势

  1. 缺乏类型安全性:宏定义是简单的文本替换,没有类型检查。例如,如果在宏定义中写错了类型名称,编译器在预处理阶段不会报错,可能导致难以调试的错误。
  2. 灵活性受限:宏定义只能基于编译期常量进行判断,对于一些复杂的编译期计算或基于模板参数的条件选择,宏定义无法满足需求。而模板元编程的std::conditional等工具可以基于模板参数进行更灵活的条件选择。