C++模板元编程实战技巧
作者 : zry
标签: C++, 模板元编程, TMP, SFINAE, Concepts, C++20
目录
- 引言
- 模板元编程基础
- SFINAE与类型萃取
- [C++20 Concepts实战](#C++20 Concepts实战)
- 编译期计算与优化
- AIDC系统中的应用案例
- 高级技巧与设计模式
- 最佳实践
- 总结
引言
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自动气象站数据收集系统中,我们利用模板元编程实现了:
- 零开销抽象:编译期多态替代运行时虚函数
- 类型安全:Concepts约束确保接口正确使用
- 编译期优化:查找表、常量计算移至编译期
- 代码复用:CRTP模式实现代码复用无运行时开销
关键要点:
| 技术 | 适用场景 | 注意事项 |
|---|---|---|
| Concepts | 接口约束 | 保持简洁,避免过度约束 |
| constexpr | 编译期计算 | C++20放宽限制,更多场景可用 |
| SFINAE | 条件模板 | C++20优先使用Concepts |
| CRTP | 静态多态 | 注意编译时间和代码膨胀 |
| 表达式模板 | 数值计算 | 控制模板实例化数量 |