C++ std::greater<&燃气轮机;wо;在一组中?
我知道std::greater是如何工作的。但是当我阅读C++14之后的std::greater API时,它有一个默认类型void。所以,如果我们不将任何模板参数传递给更大的值,它将默认为void,如下所示。但结果与预期一样,按降序排列C++ std::greater<&燃气轮机;wо;在一组中?,c++,c++14,C++,C++14,我知道std::greater是如何工作的。但是当我阅读C++14之后的std::greater API时,它有一个默认类型void。所以,如果我们不将任何模板参数传递给更大的值,它将默认为void,如下所示。但结果与预期一样,按降序排列 #include <iostream> #include <set> template< class T = void > struct greater; int main() { std::set<int
#include <iostream>
#include <set>
template< class T = void >
struct greater;
int main()
{
std::set<int, std::greater<>> s {4, 5, 6, 7}; // This transforms to std::set<int, std::greater<void>>
}
#包括
#包括
模板
结构更大;
int main()
{
std::set s{4,5,6,7};//这将转换为std::set
}
有人能解释一下这种专门化是如何工作的吗?它的工作原理是将调用操作符作为函数模板而不是函数。将旧版本与新专业进行比较:
// greater<T>
bool operator()( const T& lhs, const T& rhs ) const;
// greater<void> i.e. greater<>
template< class T, class U>
auto operator()( T&& lhs, U&& rhs ) const;
//更大
布尔运算符()(常数T和lhs、常数T和rhs)常数;
//更大,即更大
模板
自动运算符()(T&&lhs,U&&rhs)常量;
这一功能的强大之处在于能够比较不同类型的对象 例如,在给定字符串视图的情况下,这是至关重要的,您需要查找是否在集合中存储了等效的
std::string
。能够将字符串视图与std::string
进行比较允许我们不从该字符串视图创建字符串。这很好,因为创建std::string
可能会很昂贵
使用旧的比较器,它只能将
std::string
与另一个std::string
进行比较,在这种情况下,我们必须创建一个std::string
,以便从一组std::string中查找它,这是一种非常简单的技术,但我仍然对它着迷,因为它非常强大。基本思想是将特定类型的实例化推迟到模板化的操作符()的调用,而不是对特定类型的实例化更大的
假设您希望将重载集传递给函数,以便执行以下操作:
template <typename F>
void foo(F f){
f(std::string{});
f(42);
}
在您的情况下,传递greater
而不是greater
主要是为了方便,但想法是一样的greater
具有模板化的运算符()
附:…我错过了greater::operator()
的一个关键优势(详细解释见)greater
允许您比较不同类型的元素,即使它们之间没有隐式转换,或者您不想触发转换(当然您仍然需要一个可行的
)。实例化模板化函数也比实例化新类型更快,AFAICR.@einpoklum在需要实例化的greater
及其greater
加上需要实例化的操作符()的情况下是很好的。不过有趣的是,如果你知道一些参考资料,我很乐意阅读。奥丁·霍姆斯的《2017年潜水密码》演讲,@einpoklum《很好的演讲》。糟糕的配色方案,但在其他方面都非常出色。不过,我认为您记错了,根据“Bob”的说法,实例化一个函数的代价更高(~43:20)。
struct bar {
template <typename T>
void operator()(T t) {}
};
int main() {
foo(bar{});
}