C++模板元编程实战技巧

C++模板元编程实战技巧

作者 : zry
标签: C++, 模板元编程, TMP, SFINAE, Concepts, C++20


目录

  1. 引言
  2. 模板元编程基础
  3. SFINAE与类型萃取
  4. [C++20 Concepts实战](#C++20 Concepts实战)
  5. 编译期计算与优化
  6. AIDC系统中的应用案例
  7. 高级技巧与设计模式
  8. 最佳实践
  9. 总结

引言

C++模板元编程(Template Metaprogramming)是C++最强大的特性之一,它允许在编译期执行计算、类型操作和代码生成。在AIDC自动气象站数据收集系统中,我们广泛使用模板元编程来实现高性能、类型安全且零开销的抽象。

本文将结合AIDC系统的实际应用场景,深入探讨C++20时代模板元编程的实战技巧。


模板元编程基础

编译期计算原理

源代码
预处理器
模板实例化
编译期计算
类型推导
表达式求值
代码生成
优化后的IR
机器码

基础示例:编译期阶乘

cpp 复制代码
// 传统递归实现(运行时计算)
constexpr int factorial_runtime(int n) {
    return n <= 1 ? 1 : n * factorial_runtime(n - 1);
}

// 模板元编程实现(编译期计算)
template<int N>
struct Factorial {
    static constexpr int value = N * Factorial<N - 1>::value;
};

template<>
struct Factorial<0> {
    static constexpr int value = 1;
};

// C++17/20简化版本
inline constexpr int factorial_cpp17(int n) {
    if (n <= 1) return 1;
    return n * factorial_cpp17(n - 1);
}

// 使用if constexpr的C++17版本
template<int N>
constexpr int factorial_if_constexpr() {
    if constexpr (N <= 1) {
        return 1;
    } else {
        return N * factorial_if_constexpr<N - 1>();
    }
}

// 编译期验证
static_assert(Factorial<5>::value == 120);
static_assert(factorial_if_constexpr<5>() == 120);

类型列表操作

cpp 复制代码
// type_list.hpp
#pragma once
#include <type_traits>
#include <cstddef>

namespace aidc::meta {

// 类型列表容器
template<typename... Ts>
struct type_list {
    static constexpr std::size_t size = sizeof...(Ts);
};

// 获取类型列表大小
template<typename List>
struct size_of;

template<typename... Ts>
struct size_of<type_list<Ts...>> {
    static constexpr std::size_t value = sizeof...(Ts);
};

// 获取第N个类型
template<typename List, std::size_t N>
struct type_at;

template<typename T, typename... Rest>
struct type_at<type_list<T, Rest...>, 0> {
    using type = T;
};

template<typename T, typename... Rest, std::size_t N>
struct type_at<type_list<T, Rest...>, N> {
    using type = typename type_at<type_list<Rest...>, N - 1>::type;
};

// 向类型列表添加类型
template<typename List, typename T>
struct push_front;

template<typename... Ts, typename T>
struct push_front<type_list<Ts...>, T> {
    using type = type_list<T, Ts...>;
};

template<typename List, typename T>
struct push_back;

template<typename... Ts, typename T>
struct push_back<type_list<Ts...>, T> {
    using type = type_list<Ts..., T>;
};

// 检查类型是否在列表中
template<typename List, typename T>
struct contains;

template<typename T>
struct contains<type_list<>, T> : std::false_type {};

template<typename First, typename... Rest, typename T>
struct contains<type_list<First, Rest...>, T> 
    : std::conditional_t<std::is_same_v<First, T>,
                         std::true_type,
                         contains<type_list<Rest...>, T>> {};

// 过滤类型列表
template<typename List, template<typename> typename Predicate>
struct filter;

template<template<typename> typename Predicate>
struct filter<type_list<>, Predicate> {
    using type = type_list<>;
};

template<typename First, typename... Rest, template<typename> typename Predicate>
struct filter<type_list<First, Rest...>, Predicate> {
    using rest_filtered = typename filter<type_list<Rest...>, Predicate>::type;
    using type = std::conditional_t<Predicate<First>::value,
                                    typename push_front<rest_filtered, First>::type,
                                    rest_filtered>;
};

// 类型列表变换
template<typename List, template<typename> typename Transform>
struct transform;

template<template<typename> typename Transform>
struct transform<type_list<>, Transform> {
    using type = type_list<>;
};

template<typename First, typename... Rest, template<typename> typename Transform>
struct transform<type_list<First, Rest...>, Transform> {
    using transformed_first = typename Transform<First>::type;
    using rest_transformed = typename transform<type_list<Rest...>, Transform>::type;
    using type = typename push_front<rest_transformed, transformed_first>::type;
};

} // namespace aidc::meta

SFINAE与类型萃取

SFINAE基础

cpp 复制代码
// sfinae_utilities.hpp
#pragma once
#include <type_traits>
#include <utility>

namespace aidc::meta {

// void_t实现
template<typename...>
using void_t = void;

// 检测类型是否有特定成员
template<typename, typename = void_t<>>
struct has_foo : std::false_type {};

template<typename T>
struct has_foo<T, void_t<decltype(std::declval<T>().foo())>> : std::true_type {};

// 检测是否可调用
template<typename F, typename... Args>
struct is_callable {
private:
    template<typename...>
    static std::false_type test(...);
    
    template<typename Func, typename... A>
    static std::true_type test(decltype(std::declval<Func>()(std::declval<A>()...))*);
    
public:
    static constexpr bool value = decltype(test<F, Args...>(nullptr))::value;
};

// 检测是否可序列化
template<typename T, typename = void>
struct is_serializable : std::false_type {};

template<typename T>
struct is_serializable<T, void_t<
    decltype(std::declval<T>().serialize()),
    decltype(T::deserialize(std::declval<std::string_view>()))
>> : std::true_type {};

// 检测迭代器类型
template<typename T, typename = void>
struct is_iterator : std::false_type {};

template<typename T>
struct is_iterator<T, void_t<
    typename std::iterator_traits<T>::iterator_category,
    decltype(*std::declval<T>()),
    decltype(++std::declval<T&>())
>> : std::true_type {};

// 检测容器类型
template<typename T, typename = void>
struct is_container : std::false_type {};

template<typename T>
struct is_container<T, void_t<
    typename T::value_type,
    decltype(std::declval<T>().begin()),
    decltype(std::declval<T>().end()),
    decltype(std::declval<T>().size())
>> : std::true_type {};

// 类型特征检测辅助宏
#define DEFINE_HAS_MEMBER(name)                                         \
    template<typename T, typename = void>                               \
    struct has_member_##name : std::false_type {};                      \
                                                                        \
    template<typename T>                                                \
    struct has_member_##name<T, void_t<decltype(std::declval<T>().name)>> \
        : std::true_type {}

DEFINE_HAS_MEMBER(serialize);
DEFINE_HAS_MEMBER(deserialize);
DEFINE_HAS_MEMBER(to_string);
DEFINE_HAS_MEMBER(from_string);

} // namespace aidc::meta

条件函数重载

cpp 复制代码
// conditional_overloads.hpp
#pragma once
#include "sfinae_utilities.hpp"
#include <string>
#include <vector>

namespace aidc::meta {

// 根据类型特性选择不同实现

// 版本1:容器类型 - 序列化每个元素
template<typename T>
std::enable_if_t<is_container<T>::value && !std::is_same_v<T, std::string>, std::string>
to_json(const T& container) {
    std::string result = "[";
    bool first = true;
    for (const auto& item : container) {
        if (!first) result += ",";
        result += to_json(item);
        first = false;
    }
    result += "]";
    return result;
}

// 版本2:有to_string方法的类型
template<typename T>
std::enable_if_t<!is_container<T>::value && has_member_to_string<T>::value, std::string>
to_json(const T& obj) {
    return "\"" + obj.to_string() + "\"";
}

// 版本3:可直接转为字符串的类型
template<typename T>
std::enable_if_t<std::is_arithmetic_v<T>, std::string>
to_json(const T& value) {
    return std::to_string(value);
}

// 版本4:字符串类型
template<>
inline std::string to_json<std::string>(const std::string& str) {
    return "\"" + str + "\"";
}

// 使用C++20 concepts的简化版本
template<typename T>
concept Container = is_container<T>::value && !std::is_same_v<T, std::string>;

template<typename T>
concept HasToString = requires(T t) {
    { t.to_string() } -> std::convertible_to<std::string>;
};

template<typename T>
concept Arithmetic = std::is_arithmetic_v<T>;

// C++20版本
template<Container T>
std::string to_json_cpp20(const T& container) {
    // 同上实现
    return "";
}

template<HasToString T>
std::string to_json_cpp20(const T& obj) {
    return "\"" + obj.to_string() + "\"";
}

template<Arithmetic T>
std::string to_json_cpp20(const T& value) {
    return std::to_string(value);
}

} // namespace aidc::meta

C++20 Concepts实战

Concepts定义与使用

cpp 复制代码
// concepts.hpp
#pragma once
#include <concepts>
#include <type_traits>
#include <span>
#include <vector>

namespace aidc::concepts {

// 基本类型概念
template<typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;

template<typename T>
concept ByteLike = sizeof(T) == 1 && std::is_trivially_copyable_v<T>;

// 气象数据相关概念
template<typename T>
concept WeatherData = requires(T t) {
    { T::station_id } -> std::convertible_to<uint32_t>;
    { T::timestamp } -> std::convertible_to<uint64_t>;
    { t.serialize() } -> std::convertible_to<std::vector<std::byte>>;
    { T::deserialize(std::span<const std::byte>()) } -> std::same_as<T>;
};

template<typename T>
concept Serializable = requires(T t) {
    { t.serialize() } -> std::convertible_to<std::vector<std::byte>>;
} && requires {
    { T::deserialize(std::declval<std::span<const std::byte>>()) } -> std::same_as<T>;
};

template<typename T>
concept Buffer = requires(T t) {
    { t.data() } -> std::convertible_to<void*>;
    { t.size() } -> std::convertible_to<std::size_t>;
};

template<typename T>
concept ResizableBuffer = Buffer<T> && requires(T t, std::size_t n) {
    { t.resize(n) } -> std::same_as<void>;
};

// 回调概念
template<typename F, typename... Args>
concept Callback = std::invocable<F, Args...>;

template<typename F, typename R, typename... Args>
concept CallbackReturning = std::invocable<F, Args...> && 
    std::same_as<std::invoke_result_t<F, Args...>, R>;

// 资源管理概念
template<typename T>
concept Closable = requires(T t) {
    { t.close() } -> std::same_as<void>;
};

template<typename T>
concept Resettable = requires(T t) {
    { t.reset() } -> std::same_as<void>;
};

} // namespace aidc::concepts

基于Concepts的泛型代码

cpp 复制代码
// generic_buffer.hpp
#pragma once
#include "concepts.hpp"
#include <span>
#include <cstring>
#include <algorithm>

namespace aidc::buffer {

// 泛型缓冲区操作,使用concepts约束

// 安全的内存拷贝
template<concepts::ByteLike Dest, concepts::ByteLike Src>
void safe_copy(std::span<Dest> dest, std::span<const Src> src) {
    static_assert(sizeof(Dest) == sizeof(Src), "Byte types must be same size");
    
    std::size_t copy_size = std::min(dest.size(), src.size());
    std::memcpy(dest.data(), src.data(), copy_size);
}

// 序列化到缓冲区
template<concepts::Serializable T, concepts::ResizableBuffer Buffer>
void serialize_to(const T& obj, Buffer& buffer) {
    auto data = obj.serialize();
    buffer.resize(data.size());
    safe_copy(std::span(buffer), std::span(data));
}

// 从缓冲区反序列化
template<concepts::Serializable T, concepts::Buffer Buffer>
T deserialize_from(const Buffer& buffer) {
    auto span = std::span(reinterpret_cast<const std::byte*>(buffer.data()), 
                          buffer.size());
    return T::deserialize(span);
}

// 数值数据打包
template<concepts::Numeric T, concepts::ByteLike Byte = std::byte>
std::vector<Byte> pack_numeric(T value) {
    std::vector<Byte> result(sizeof(T));
    std::memcpy(result.data(), &value, sizeof(T));
    return result;
}

template<concepts::Numeric T, concepts::ByteLike Byte>
T unpack_numeric(std::span<const Byte> bytes) {
    T value{};
    std::memcpy(&value, bytes.data(), std::min(bytes.size(), sizeof(T)));
    return value;
}

// 批量数值处理
template<concepts::Numeric T, typename Func>
requires std::invocable<Func, T>
void process_numeric_batch(std::span<T> data, Func&& processor) {
    std::for_each(data.begin(), data.end(), std::forward<Func>(processor));
}

// 带约束的类模板
template<concepts::WeatherData T>
class WeatherDataProcessor {
public:
    void process(const T& data) {
        validate(data);
        transform(data);
        store(data);
    }
    
    std::vector<T> batch_process(std::span<const T> batch) {
        std::vector<T> results;
        results.reserve(batch.size());
        
        for (const auto& item : batch) {
            results.push_back(process_single(item));
        }
        
        return results;
    }

private:
    void validate(const T& data) {
        // 验证数据有效性
    }
    
    void transform(const T& data) {
        // 数据转换
    }
    
    void store(const T& data) {
        // 存储数据
    }
    
    T process_single(const T& data) {
        // 单条处理逻辑
        return data;
    }
};

} // namespace aidc::buffer

编译期计算与优化

编译期字符串处理

cpp 复制代码
// compile_time_string.hpp
#pragma once
#include <array>
#include <algorithm>
#include <string_view>

namespace aidc::meta {

// 编译期字符串
template<std::size_t N>
struct FixedString {
    std::array<char, N + 1> data{};
    
    constexpr FixedString(const char (&str)[N + 1]) {
        std::copy_n(str, N + 1, data.begin());
    }
    
    constexpr std::size_t size() const { return N; }
    constexpr const char* c_str() const { return data.data(); }
    constexpr std::string_view view() const { 
        return std::string_view(data.data(), N); 
    }
    
    // 编译期比较
    constexpr bool operator==(const FixedString& other) const {
        return data == other.data;
    }
    
    // 编译期哈希
    constexpr std::size_t hash() const {
        std::size_t h = 0;
        for (std::size_t i = 0; i < N; ++i) {
            h = h * 131 + data[i];
        }
        return h;
    }
};

// 推导指引
template<std::size_t N>
FixedString(const char (&)[N]) -> FixedString<N - 1>;

// 编译期字符串拼接
template<std::size_t N1, std::size_t N2>
constexpr auto operator+(const FixedString<N1>& a, const FixedString<N2>& b) {
    FixedString<N1 + N2> result{};
    std::copy_n(a.data.begin(), N1, result.data.begin());
    std::copy_n(b.data.begin(), N2, result.data.begin() + N1);
    result.data[N1 + N2] = '\0';
    return result;
}

// 编译期字符串哈希
inline constexpr std::size_t hash_string(std::string_view str) {
    std::size_t hash = 0;
    for (char c : str) {
        hash = hash * 131 + c;
    }
    return hash;
}

// 编译期switch实现
template<auto Value>
constexpr auto ct_value = Value;

template<FixedString Str>
constexpr auto ct_hash = Str.hash();

// 使用示例
constexpr FixedString station_prefix = "STATION_";
constexpr FixedString station_id = "001";
constexpr auto full_name = station_prefix + station_id;

static_assert(full_name.size() == 12);
static_assert(full_name.hash() == hash_string("STATION_001"));

} // namespace aidc::meta

编译期配置表

cpp 复制代码
// compile_time_config.hpp
#pragma once
#include "compile_time_string.hpp"
#include <tuple>
#include <variant>

namespace aidc::config {

// 配置项类型
template<FixedString Name, typename T, T DefaultValue>
struct ConfigItem {
    static constexpr auto name = Name;
    using type = T;
    static constexpr T default_value = DefaultValue;
};

// 配置表
template<typename... Items>
class ConfigTable {
public:
    using ItemList = aidc::meta::type_list<Items...>;
    
    // 编译期查找类型
    template<FixedString Name>
    using find_type = typename find_item<Name>::type::type;
    
    // 编译期获取默认值
    template<FixedString Name>
    static constexpr auto default_value = find_item<Name>::type::default_value;
    
    // 运行时获取值
    template<FixedString Name>
    auto get() const -> find_type<Name> {
        return std::get<index_of<Name>()>(values_);
    }
    
    template<FixedString Name>
    void set(find_type<Name> value) {
        std::get<index_of<Name>()>(values_) = value;
    }
    
    // 从字符串名称获取值
    template<typename T>
    std::optional<T> get_by_name(std::string_view name) const {
        return get_by_name_impl<T, Items...>(name);
    }

private:
    template<FixedString Name>
    struct find_item;
    
    template<FixedString Name, typename First, typename... Rest>
    struct find_item<Name, First, Rest...> {
        using type = std::conditional_t<First::name == Name,
                                        First,
                                        typename find_item<Name, Rest...>::type>;
    };
    
    template<FixedString Name>
    struct find_item<Name> {
        static_assert(sizeof...(Items) == 0, "Config item not found");
    };
    
    template<FixedString Name>
    static constexpr std::size_t index_of() {
        return index_of_impl<Name, 0, Items...>();
    }
    
    template<FixedString Name, std::size_t I, typename First, typename... Rest>
    static constexpr std::size_t index_of_impl() {
        if constexpr (First::name == Name) {
            return I;
        } else {
            return index_of_impl<Name, I + 1, Rest...>();
        }
    }
    
    template<FixedString Name, std::size_t I>
    static constexpr std::size_t index_of_impl() {
        static_assert(sizeof...(Items) > 0, "Config item not found");
        return I;
    }
    
    template<typename T, typename First, typename... Rest>
    std::optional<T> get_by_name_impl(std::string_view name) const {
        if (First::name.view() == name) {
            if constexpr (std::is_same_v<typename First::type, T>) {
                return std::get<index_of<First::name>()>(values_);
            }
        }
        if constexpr (sizeof...(Rest) > 0) {
            return get_by_name_impl<T, Rest...>(name);
        }
        return std::nullopt;
    }
    
    std::tuple<typename Items::type...> values_ = {Items::default_value...};
};

// AIDC配置定义
using AidcConfig = ConfigTable<
    ConfigItem<FixedString("grpc_timeout_ms"), int, 5000>,
    ConfigItem<FixedString("max_connections"), int, 10000>,
    ConfigItem<FixedString("buffer_size"), std::size_t, 65536>,
    ConfigItem<FixedString("enable_compression"), bool, true>
>;

} // namespace aidc::config

AIDC系统中的应用案例

气象数据类型系统

cpp 复制代码
// weather_types.hpp
#pragma once
#include "concepts.hpp"
#include <cstdint>
#include <array>
#include <span>

namespace aidc::weather {

// 传感器类型枚举(编译期定义)
enum class SensorType : uint8_t {
    TEMPERATURE = 0x01,
    HUMIDITY = 0x02,
    PRESSURE = 0x03,
    WIND_SPEED = 0x04,
    WIND_DIRECTION = 0x05,
    RAINFALL = 0x06,
    VISIBILITY = 0x07,
    COUNT
};

// 编译期传感器元数据
template<SensorType Type>
struct SensorMetadata;

#define DEFINE_SENSOR_METADATA(type, name_str, unit_str, prec)  \
    template<>                                                  \
    struct SensorMetadata<SensorType::type> {                   \
        static constexpr auto name = FixedString(name_str);     \
        static constexpr auto unit = FixedString(unit_str);     \
        static constexpr int precision = prec;                  \
        static constexpr SensorType type_value = SensorType::type; \
    }

DEFINE_SENSOR_METADATA(TEMPERATURE, "temperature", "celsius", 2);
DEFINE_SENSOR_METADATA(HUMIDITY, "humidity", "percent", 1);
DEFINE_SENSOR_METADATA(PRESSURE, "pressure", "hpa", 2);
DEFINE_SENSOR_METADATA(WIND_SPEED, "wind_speed", "m/s", 1);
DEFINE_SENSOR_METADATA(WIND_DIRECTION, "wind_direction", "degrees", 0);
DEFINE_SENSOR_METADATA(RAINFALL, "rainfall", "mm", 2);
DEFINE_SENSOR_METADATA(VISIBILITY, "visibility", "m", 0);

// 泛型传感器数据模板
template<SensorType Type>
requires (static_cast<std::size_t>(Type) < 
          static_cast<std::size_t>(SensorType::COUNT))
class SensorReading {
public:
    using Metadata = SensorMetadata<Type>;
    
    uint64_t timestamp;
    uint32_t station_id;
    double value;
    uint8_t quality_flag;
    
    // 编译期获取元数据
    static constexpr std::string_view sensor_name() {
        return Metadata::name.view();
    }
    
    static constexpr std::string_view unit() {
        return Metadata::unit.view();
    }
    
    static constexpr int precision() {
        return Metadata::precision;
    }
    
    // 序列化(实现WeatherData概念)
    std::vector<std::byte> serialize() const {
        std::vector<std::byte> result(sizeof(SensorReading));
        std::memcpy(result.data(), this, sizeof(SensorReading));
        return result;
    }
    
    static SensorReading deserialize(std::span<const std::byte> data) {
        SensorReading reading{};
        std::memcpy(&reading, data.data(), 
                   std::min(data.size(), sizeof(SensorReading)));
        return reading;
    }
};

// 使用类型列表定义所有传感器类型
using AllSensorTypes = aidc::meta::type_list<
    SensorReading<SensorType::TEMPERATURE>,
    SensorReading<SensorType::HUMIDITY>,
    SensorReading<SensorType::PRESSURE>,
    SensorReading<SensorType::WIND_SPEED>,
    SensorReading<SensorType::WIND_DIRECTION>,
    SensorReading<SensorType::RAINFALL>,
    SensorReading<SensorType::VISIBILITY>
>;

// 编译期传感器类型分发
template<SensorType Type>
constexpr std::size_t sensor_type_index() {
    return static_cast<std::size_t>(Type) - 1;
}

// 变体类型包装
using SensorVariant = std::variant<
    SensorReading<SensorType::TEMPERATURE>,
    SensorReading<SensorType::HUMIDITY>,
    SensorReading<SensorType::PRESSURE>,
    SensorReading<SensorType::WIND_SPEED>,
    SensorReading<SensorType::WIND_DIRECTION>,
    SensorReading<SensorType::RAINFALL>,
    SensorReading<SensorType::VISIBILITY>
>;

} // namespace aidc::weather

编译期协议解析

cpp 复制代码
// protocol_parser.hpp
#pragma once
#include "weather_types.hpp"
#include <span>
#include <expected>

namespace aidc::protocol {

// 编译期消息格式定义
template<std::size_t Offset, typename T>
struct Field {
    static constexpr std::size_t offset = Offset;
    using type = T;
    static constexpr std::size_t size = sizeof(T);
};

// 消息结构定义
template<typename... Fields>
struct MessageLayout {
    static constexpr std::size_t total_size = (Fields::size + ...);
    
    // 编译期查找字段偏移
    template<std::size_t TargetOffset>
    using field_at = typename find_field<TargetOffset, Fields...>::type;
    
    template<std::size_t TargetOffset, typename First, typename... Rest>
    struct find_field {
        using type = std::conditional_t<TargetOffset == First::offset,
                                        First,
                                        typename find_field<TargetOffset, Rest...>::type>;
    };
};

// AIDC气象数据包格式
using WeatherPacketLayout = MessageLayout<
    Field<0, uint32_t>,      // 包头标识
    Field<4, uint32_t>,      // 站号
    Field<8, uint64_t>,      // 时间戳
    Field<16, uint8_t>,      // 传感器类型
    Field<17, double>,       // 数据值
    Field<25, uint8_t>,      // 质量标识
    Field<26, uint16_t>      // 校验和
>;

// 编译期协议解析器
template<typename Layout>
class StaticParser {
public:
    static constexpr std::size_t packet_size = Layout::total_size;
    
    template<std::size_t Offset, typename T = typename Layout::template field_at<Offset>::type>
    static T read_field(std::span<const std::byte> data) {
        static_assert(Offset + sizeof(T) <= packet_size, "Field out of bounds");
        
        T value;
        std::memcpy(&value, data.data() + Offset, sizeof(T));
        return value;
    }
    
    template<std::size_t Offset, typename T = typename Layout::template field_at<Offset>::type>
    static void write_field(std::span<std::byte> data, const T& value) {
        static_assert(Offset + sizeof(T) <= packet_size, "Field out of bounds");
        std::memcpy(data.data() + Offset, &value, sizeof(T));
    }
    
    // 编译期校验包完整性
    static bool validate_checksum(std::span<const std::byte> data) {
        if (data.size() != packet_size) return false;
        
        uint16_t checksum = 0;
        for (std::size_t i = 0; i < packet_size - 2; ++i) {
            checksum += static_cast<uint8_t>(data[i]);
        }
        
        uint16_t expected = read_field<26>(data);
        return checksum == expected;
    }
};

// 类型安全的解析结果
template<typename T>
using ParseResult = std::expected<T, ParseError>;

enum class ParseError {
    INVALID_SIZE,
    INVALID_CHECKSUM,
    UNKNOWN_SENSOR_TYPE,
    MALFORMED_DATA
};

// 气象数据包解析
class WeatherPacketParser {
public:
    using Parser = StaticParser<WeatherPacketLayout>;
    
    static ParseResult<SensorVariant> parse(std::span<const std::byte> data) {
        if (data.size() != Parser::packet_size) {
            return std::unexpected(ParseError::INVALID_SIZE);
        }
        
        if (!Parser::validate_checksum(data)) {
            return std::unexpected(ParseError::INVALID_CHECKSUM);
        }
        
        auto sensor_type = static_cast<SensorType>(
            Parser::template read_field<16>(data));
        
        return parse_by_type(sensor_type, data);
    }

private:
    static ParseResult<SensorVariant> parse_by_type(
        SensorType type, 
        std::span<const std::byte> data) {
        
        switch (type) {
            case SensorType::TEMPERATURE:
                return parse_sensor<SensorType::TEMPERATURE>(data);
            case SensorType::HUMIDITY:
                return parse_sensor<SensorType::HUMIDITY>(data);
            case SensorType::PRESSURE:
                return parse_sensor<SensorType::PRESSURE>(data);
            case SensorType::WIND_SPEED:
                return parse_sensor<SensorType::WIND_SPEED>(data);
            case SensorType::WIND_DIRECTION:
                return parse_sensor<SensorType::WIND_DIRECTION>(data);
            case SensorType::RAINFALL:
                return parse_sensor<SensorType::RAINFALL>(data);
            case SensorType::VISIBILITY:
                return parse_sensor<SensorType::VISIBILITY>(data);
            default:
                return std::unexpected(ParseError::UNKNOWN_SENSOR_TYPE);
        }
    }
    
    template<SensorType Type>
    static SensorVariant parse_sensor(std::span<const std::byte> data) {
        using Reading = weather::SensorReading<Type>;
        Reading reading;
        
        reading.station_id = Parser::template read_field<4>(data);
        reading.timestamp = Parser::template read_field<8>(data);
        reading.value = Parser::template read_field<17>(data);
        reading.quality_flag = Parser::template read_field<25>(data);
        
        return reading;
    }
};

} // namespace aidc::protocol

高级技巧与设计模式

CRTP模式应用

cpp 复制代码
// crtp_mixins.hpp
#pragma once
#include <type_traits>

namespace aidc::patterns {

// 单例CRTP基类
template<typename Derived>
class Singleton {
public:
    static Derived& instance() {
        static Derived instance;
        return instance;
    }
    
protected:
    Singleton() = default;
    ~Singleton() = default;
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
};

// 计数器CRTP
template<typename Derived>
class InstanceCounter {
public:
    InstanceCounter() { ++count(); }
    InstanceCounter(const InstanceCounter&) { ++count(); }
    ~InstanceCounter() { --count(); }
    
    static std::size_t instance_count() { return count(); }

private:
    static std::size_t& count() {
        static std::size_t c = 0;
        return c;
    }
};

// 可比较CRTP
template<typename Derived>
class Comparable {
public:
    bool operator!=(const Derived& other) const {
        return !static_cast<const Derived*>(this)->operator==(other);
    }
    
    bool operator<(const Derived& other) const {
        return static_cast<const Derived*>(this)->compare(other) < 0;
    }
    
    bool operator>(const Derived& other) const {
        return static_cast<const Derived*>(this)->compare(other) > 0;
    }
    
    bool operator<=(const Derived& other) const {
        return !operator>(other);
    }
    
    bool operator>=(const Derived& other) const {
        return !operator<(other);
    }
};

// 访问者模式CRTP
template<typename Derived, typename ReturnType = void>
class Visitor {
public:
    template<typename Visitable>
    ReturnType visit(Visitable& v) {
        return v.accept(static_cast<Derived*>(this));
    }
};

// 策略模式CRTP
template<typename Derived>
class Strategy {
public:
    template<typename... Args>
    auto execute(Args&&... args) {
        return static_cast<Derived*>(this)->algorithm(
            std::forward<Args>(args)...);
    }
};

} // namespace aidc::patterns

表达式模板

cpp 复制代码
// expression_templates.hpp
#pragma once
#include <vector>
#include <cassert>

namespace aidc::expr {

// 表达式基类
template<typename Derived>
class Expression {
public:
    const Derived& derived() const {
        return static_cast<const Derived&>(*this);
    }
    
    auto operator[](std::size_t i) const {
        return derived()[i];
    }
    
    std::size_t size() const {
        return derived().size();
    }
};

// 向量包装
template<typename T>
class Vector : public Expression<Vector<T>> {
public:
    explicit Vector(std::size_t n) : data_(n) {}
    Vector(std::initializer_list<T> init) : data_(init) {}
    
    T operator[](std::size_t i) const { return data_[i]; }
    T& operator[](std::size_t i) { return data_[i]; }
    std::size_t size() const { return data_.size(); }
    
    // 延迟赋值
    template<typename Expr>
    Vector& operator=(const Expression<Expr>& expr) {
        const Expr& e = expr.derived();
        assert(size() == e.size());
        
        for (std::size_t i = 0; i < size(); ++i) {
            data_[i] = e[i];
        }
        return *this;
    }

private:
    std::vector<T> data_;
};

// 向量加法表达式
template<typename Left, typename Right>
class VectorAdd : public Expression<VectorAdd<Left, Right>> {
public:
    VectorAdd(const Expression<Left>& l, const Expression<Right>& r)
        : left_(l.derived()), right_(r.derived()) {
        assert(left_.size() == right_.size());
    }
    
    auto operator[](std::size_t i) const {
        return left_[i] + right_[i];
    }
    
    std::size_t size() const { return left_.size(); }

private:
    const Left& left_;
    const Right& right_;
};

// 向量乘法(逐元素)
template<typename Left, typename Right>
class VectorMul : public Expression<VectorMul<Left, Right>> {
public:
    VectorMul(const Expression<Left>& l, const Expression<Right>& r)
        : left_(l.derived()), right_(r.derived()) {
        assert(left_.size() == right_.size());
    }
    
    auto operator[](std::size_t i) const {
        return left_[i] * right_[i];
    }
    
    std::size_t size() const { return left_.size(); }

private:
    const Left& left_;
    const Right& right_;
};

// 标量乘法
template<typename Expr, typename Scalar>
class ScalarMul : public Expression<ScalarMul<Expr, Scalar>> {
public:
    ScalarMul(const Expression<Expr>& e, Scalar s)
        : expr_(e.derived()), scalar_(s) {}
    
    auto operator[](std::size_t i) const {
        return expr_[i] * scalar_;
    }
    
    std::size_t size() const { return expr_.size(); }

private:
    const Expr& expr_;
    Scalar scalar_;
};

// 运算符重载
template<typename L, typename R>
VectorAdd<L, R> operator+(const Expression<L>& l, const Expression<R>& r) {
    return VectorAdd<L, R>(l, r);
}

template<typename L, typename R>
VectorMul<L, R> operator*(const Expression<L>& l, const Expression<R>& r) {
    return VectorMul<L, R>(l, r);
}

template<typename E, typename S>
ScalarMul<E, S> operator*(const Expression<E>& e, S s) {
    return ScalarMul<E, S>(e, s);
}

template<typename E, typename S>
ScalarMul<E, S> operator*(S s, const Expression<E>& e) {
    return ScalarMul<E, S>(e, s);
}

// 使用示例:v3 = v1 + v2 * 2.0 + v1 * v2;
// 无临时对象,延迟计算

} // namespace aidc::expr

最佳实践

1. 编译错误诊断

cpp 复制代码
// static_assert_helpers.hpp
#pragma once
#include <type_traits>

namespace aidc::meta {

// 提供友好的编译错误信息
template<typename T>
struct always_false : std::false_type {};

template<auto V>
struct always_false_value : std::false_type {};

// 受约束模板的错误处理
template<typename T>
void process_unsupported_type() {
    static_assert(always_false<T>::value, 
                  "Type T is not supported for processing. "
                  "Ensure it satisfies the required concept.");
}

// 概念约束的错误信息
template<typename T>
    requires std::integral<T> || std::floating_point<T>
void process_numeric(T value) {
    // 处理数值类型
}

template<typename T>
void process_numeric(T value) {
    static_assert(always_false<T>::value,
                  "process_numeric requires a numeric type (integral or floating_point)");
}

} // namespace aidc::meta

2. 编译期性能优化

cpp 复制代码
// compile_time_optimization.hpp
#pragma once
#include <array>

namespace aidc::meta {

// 使用constexpr lookup table替代运行时计算
inline constexpr auto generate_crc32_table() {
    std::array<uint32_t, 256> table{};
    
    for (uint32_t i = 0; i < 256; ++i) {
        uint32_t crc = i;
        for (int j = 0; j < 8; ++j) {
            crc = (crc >> 1) ^ (0xEDB88320 & -(crc & 1));
        }
        table[i] = crc;
    }
    
    return table;
}

inline constexpr auto crc32_table = generate_crc32_table();

// 编译期计算CRC32
constexpr uint32_t crc32_compile_time(std::string_view data) {
    uint32_t crc = 0xFFFFFFFF;
    
    for (char c : data) {
        crc = (crc >> 8) ^ crc32_table[(crc ^ static_cast<uint8_t>(c)) & 0xFF];
    }
    
    return ~crc;
}

// 使用示例:编译期计算哈希
inline constexpr uint32_t protocol_magic = crc32_compile_time("AIDC_PROTOCOL_V1");

} // namespace aidc::meta

总结

C++模板元编程是构建高性能、类型安全系统的强大工具。在AIDC自动气象站数据收集系统中,我们利用模板元编程实现了:

  1. 零开销抽象:编译期多态替代运行时虚函数
  2. 类型安全:Concepts约束确保接口正确使用
  3. 编译期优化:查找表、常量计算移至编译期
  4. 代码复用:CRTP模式实现代码复用无运行时开销

关键要点:

技术 适用场景 注意事项
Concepts 接口约束 保持简洁,避免过度约束
constexpr 编译期计算 C++20放宽限制,更多场景可用
SFINAE 条件模板 C++20优先使用Concepts
CRTP 静态多态 注意编译时间和代码膨胀
表达式模板 数值计算 控制模板实例化数量

https://github.com/0voice

相关推荐
ambition202422 小时前
斐波那契取模问题的深入分析:为什么提前取模是关键的
c语言·数据结构·c++·算法·图论
艾莉丝努力练剑2 小时前
C++ 核心编程练习:从基础语法到递归、重载与宏定义
linux·运维·服务器·c语言·c++·学习
taxunjishu2 小时前
AGV 与伺服协同控制Profinet 转 Modbus TCP塔讯智能网关仓储场景应用实践
网络·网络协议
VOOHU 沃虎2 小时前
AI服务器多相电源设计:组合电感如何提升CPU/GPU供电效率
服务器·网络·信息与通信
牢姐与蒯2 小时前
模板的进阶
c++
小樱花的樱花2 小时前
1 项目概述
开发语言·c++·qt·ui
ALex_zry2 小时前
gRPC服务熔断与限流设计
c++·安全·grpc
I疯子2 小时前
2026-04-08 打卡第 5 天
开发语言·windows·python
情绪雪3 小时前
IP 协议基本原理
网络·网络协议·tcp/ip