You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++中替代宏实现带类型检查的可赋值Lisp风格cons访问

解决方案:C++模板函数实现带类型检查的Lisp风格访问器

核心思路

用C++模板函数返回成员引用,既保留左值可赋值特性,又通过编译期检查确保类型合法性,完全替代预处理器宏。

实现步骤

1. 定义Cons结构体

先明确你的Cons结构体基础定义:

struct Cons {
    Cons* car;
    Cons* cdr;

    // 可选:添加构造函数简化实例创建
    Cons(Cons* car_ptr = nullptr, Cons* cdr_ptr = nullptr)
        : car(car_ptr), cdr(cdr_ptr) {}
};

2. 基础访问函数(带类型检查)

编写模板函数car和cdr,通过编译期校验限制仅接受Cons指针,返回成员引用以支持赋值:

C++11+ 版本
#include <type_traits>

// 非const版本:支持赋值操作
template<typename T>
constexpr auto& car(T* cons) noexcept {
    static_assert(std::is_same_v<std::decay_t<T>, Cons>, 
                  "car() requires a pointer to Cons");
    return cons->car;
}

template<typename T>
constexpr auto& cdr(T* cons) noexcept {
    static_assert(std::is_same_v<std::decay_t<T>, Cons>, 
                  "cdr() requires a pointer to Cons");
    return cons->cdr;
}

// const版本:只读访问
template<typename T>
constexpr const auto& car(const T* cons) noexcept {
    static_assert(std::is_same_v<std::decay_t<T>, Cons>, 
                  "car() requires a const pointer to Cons");
    return cons->car;
}

template<typename T>
constexpr const auto& cdr(const T* cons) noexcept {
    static_assert(std::is_same_v<std::decay_t<T>, Cons>, 
                  "cdr() requires a const pointer to Cons");
    return cons->cdr;
}
C++20+ 版本(用概念简化)

如果项目支持C++20,可使用概念让代码更简洁,错误信息更友好:

#include <concepts>

template<typename T>
concept ConsPointer = std::is_pointer_v<T> && 
                      std::is_same_v<std::decay_t<std::remove_pointer_t<T>>, Cons>;

// 非const版本
constexpr auto& car(ConsPointer auto cons) noexcept {
    return cons->car;
}

constexpr auto& cdr(ConsPointer auto cons) noexcept {
    return cons->cdr;
}

// const版本
constexpr const auto& car(const ConsPointer auto cons) noexcept {
    return cons->car;
}

constexpr const auto& cdr(const ConsPointer auto cons) noexcept {
    return cons->cdr;
}

3. 组合访问函数

基于基础函数实现Lisp风格的组合访问器(如cadr、caddr等),同样返回引用支持赋值:

// cadr = car(cdr(x))
template<typename T>
constexpr auto& cadr(T* cons) noexcept {
    return car(cdr(cons));
}

template<typename T>
constexpr const auto& cadr(const T* cons) noexcept {
    return car(cdr(cons));
}

// caddr = car(cdr(cdr(x)))
template<typename T>
constexpr auto& caddr(T* cons) noexcept {
    return car(cdr(cdr(cons)));
}

template<typename T>
constexpr const auto& caddr(const T* cons) noexcept {
    return car(cdr(cdr(cons)));
}

// 以此类推实现caar、cdar、cddr等,直到你需要的深度

使用示例

int main() {
    // 创建链表结构:(A (B C))
    Cons C;
    Cons B(&C, nullptr);
    Cons A(&B, nullptr);

    // 赋值操作
    Cons new_node;
    caddr(&A) = &new_node; // 等价于 A.cdr->cdr->car = &new_node;

    // 读取操作
    Cons* node = caddr(&A);

    // 传入非Cons指针会触发编译错误
    // int* p = nullptr;
    // car(p); // 编译失败,提示"car() requires a pointer to Cons"
    return 0;
}

方案优势

  • 类型安全:编译期直接拦截非Cons指针的调用,错误信息清晰可定位,避免了宏的模糊报错问题。
  • 左值支持:所有函数返回成员的引用,完全兼容caddr(x) = y这类赋值操作,和原宏的用法一致。
  • 无预处理器依赖:纯C++模板实现,规避了宏的各种弊端(如无类型检查、展开歧义、调试困难等)。

内容的提问来源于stack exchange,提问作者dragoncoder047

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 12:02:04