C++ std库类型作模板参数及花括号{}语法使用问题咨询
std::less模板使用相关问题解答 std命名空间下的函数对象类型作为模板参数的用法
C++模板的类型形参不限制类型的来源,只要模板实例化位置用到的类型名可见、合法即可传入。
std::less是标准库在<functional>头文件中定义的类模板,它的所有合法特化(包括std::less<int>、std::less<double>这类指定了比较参数类型的版本,以及默认的std::less<>即std::less<void>特化)本质都是普通类类型,和开发者自定义的空比较器类没有区别,天然满足类型模板参数的传参要求。- 示例代码中模板定义
template <typename A, typename B, typename C = std::less<>>,就是将std::less<>设置为第三个类型形参C的默认类型。调用fun时如果不显式指定第三个模板实参,编译器就会自动使用std::less<>作为C的实际类型。 - 示例中用到的
std::less<>有特殊行为:它是针对void的特化版本,其重载的operator()是成员函数模板,调用时才会根据传入的两个实参自动推导类型,匹配公共比较类型后再执行比较,不会提前将参数固定转换为某一类型,因此不会出现std::less<int>比较时浮点数被截断为整数的问题。
类型名后花括号{}的作用
示例中两处跟在类型名后的{}本质都是C++11引入的列表初始化语法,作用是构造对应类型的值初始化临时对象,不同场景下的具体效果如下:
- 函数参数声明
C cmp = C{}中的C{}:用于构造一个C类型的临时对象,作为形参cmp的默认实参。也就是说调用fun时如果不传入第三个实参,编译器会自动默认构造一个C类型的实例传入。由于所有std::less特化都是无成员变量的空类,默认构造的实例没有任何内部状态,调用其比较逻辑的行为完全一致。 - 表达式
std::less<double>{}(5, 5.6)中的std::less<double>{}:同样是先默认构造一个std::less<double>类型的临时实例,后面紧跟的(5, 5.6)是调用该临时实例的重载operator(),传入两个参数执行比较。 - 这里使用
{}而非老式的()做值初始化是现代C的推荐写法,二者对于空类的初始化效果完全等价,但{}不会触发C的“最令人烦恼的解析”歧义——部分场景下T()会被编译器误解析为函数声明,T{}不存在这个问题。
示例中不同比较表达式的结果差异,本质是比较器的参数类型不同导致隐式转换行为不同:
std::less<int>{}的比较运算符接收两个int参数,传入浮点数时会先截断为整数,因此std::less<int>{}(5, 5.6)实际比较的是5 < 5,返回false,编译器通常会给出隐式类型转换警告;std::less<double>{}的比较运算符接收两个double参数,传入整数会自动提升为double,因此std::less<double>{}(5, 5.6)比较的是5.0 < 5.6,返回true;std::less<int>{}(5.6, 5.7)中两个浮点数都会被截断为5,比较5 < 5返回false;std::less{}即std::less<void>的实例,会自动推导两个参数的公共类型为double再比较,因此std::less{}(5, 5.6)比较的是5.0 < 5.6,返回true,无截断问题。
内容的提问来源于stack exchange,提问作者lpnorm
相关产品推荐
相关产品推荐

