C++ -- 型号比对和constexpr
1、std::is_samestd::is_same是 C 标准库type_traits头文件中提供的一个类型特征Type Trait模板类。它的主要作用是在编译期严格判断两个类型是否完全相同。std::is_same是一个模板结构体接受两个类型参数T1和T2。它包含一个静态成员常量value如果T1和T2是完全相同的类型std::is_sameT1, T2::value为true。否则为false。从 C17 开始引入了变量模板std::is_same_v它是::value的简写形式使用更加便捷。#include iostream #include type_traits int main() { // C11/14 写法 std::cout std::boolalpha; std::cout int vs int: std::is_sameint, int::value std::endl; // true std::cout int vs double: std::is_sameint, double::value std::endl; // false // C17 及以后推荐写法 (更简洁) std::cout int vs int (v): std::is_same_vint, int std::endl; // true return 0; }std::is_same进行的是字面意义上的严格类型比较它不会进行任何隐式类型转换或类型归一化。以下情况均被视为不同类型// 这些都会返回 false std::is_same_vint, const int; // false std::is_same_vint, int; // false std::is_same_vchar, signed char; // false (注意这点很多初学者会误以为为 true)2、if constexprif constexpr是 C17 引入的一项关键特性用于在编译期进行条件判断。它允许编译器根据常量表达式的值选择性地实例化代码分支。与传统的运行时if语句或预处理器宏如#ifdef不同if constexpr的核心优势在于未被选中的分支会被完全丢弃不参与编译甚至不会进行语法检查。if constexpr (condition) { // 当 condition 为 true 时编译此分支 } else { // 当 condition 为 false 时编译此分支可选 }condition必须是一个编译期常量表达式constexpr expression例如std::is_integral_vT、字面量比较或constexpr变量。行为如果条件为true编译器只实例化if块内的代码。如果条件为false编译器只实例化else块内的代码如果有。被丢弃的分支被视为“不存在”即使其中包含语法错误或针对当前类型非法的操作如调用不存在的成员函数也不会导致编译错误。templatetypename T void process(T val) { if constexpr (std::is_same_vT, int) { std::cout 处理整数: val std::endl; } else if constexpr (std::is_same_vT, double) { std::cout 处理浮点数: val std::endl; } else { std::cout 处理其他类型 std::endl; } }使用std::enable_if控制函数重载这是 SFINAE 最经典的应用。通过std::enable_if可以根据类型特征决定是否让某个模板参与重载决议。SFINAESubstitution Failure Is Not An Error替换失败并非错误机制的技术手段。#include iostream #include type_traits // 只有当 T 是整数类型时此函数才参与重载 templatetypename T typename std::enable_ifstd::is_integralT::value, void::type process(T value) { std::cout Processing integer: value std::endl; } // 只有当 T 是浮点类型时此函数才参与重载 templatetypename T typename std::enable_ifstd::is_floating_pointT::value, void::type process(T value) { std::cout Processing float: value std::endl; } int main() { process(42); // 调用整数版本 process(3.14); // 调用浮点版本 // process(hello); // 编译错误没有匹配的重载因为 string 既不是 integral 也不是 floating_point return 0; }typename std::enable_ifstd::is_integralT::value, void::type它的核心作用是只有当模板参数T是整数类型时这个表达式才代表一个有效的类型即void如果T不是整数类型该表达式会导致编译时的“替换失败”从而将当前的函数或类特化从重载候选集中静默移除。A.std::is_integralT::value含义这是一个类型特征Type Trait用于判断类型T是否为整数类型如int,char,long,bool等。结果它是一个编译期常量布尔值如果T是整数类型结果为true。如果T不是整数类型如float,double,class等结果为false。B.std::enable_ifCondition, Type定义std::enable_if是一个模板结构体定义在type_traits头文件中。它接受两个模板参数B(Condition)一个布尔值。T(Type)一个类型默认值为void。行为逻辑如果B为truestd::enable_if内部会定义一个公共成员类型别名type其等价于第二个参数T。如果B为falsestd::enable_if内部没有定义任何名为type的成员。C.::type含义尝试访问std::enable_if结构体中的成员类型type。关键点当std::is_integralT::value为true时::type存在且等价于void因为第二个参数传的是void。当std::is_integralT::value为false时::type不存在。D.typename含义告诉编译器后面的...::type是一个类型名称而不是静态成员变量或其他东西。因为在模板中依赖型名称dependent name默认不被视为类型必须显式加上typename。情况 1调用myFunction(10)此时T推导为intstd::is_integralint::value为true。std::enable_iftrue, void被实例化。因为条件为真std::enable_if内部定义了typedef void type;。typename ... ::type成功解析为void。函数签名变为void myFunction(int t)。结果该函数是一个合法的重载候选参与编译。