C++ 选择性预定义函子初始化 [复制]

C++ selective predefined functor initializaiton [duplicate]

提问人:Mikhail 提问时间:2/25/2023 最后编辑:DailyLearnerMikhail 更新时间:2/25/2023 访问量:71

问:

预定义的函子需要就地实例化(带空括号)才能在算法中使用,但不能用作容器适配器(如 priority_queue)的类型参数。为什么会有这种差异?

#include <queue>
#include <vector>
#include <numeric>

int main(){

   std::priority_queue<int, std::vector<int>,
   // parentheses are NOT needed here: std::greater<>
                                            std::greater<>> pq;
   pq.push(1);
   pq.push(2);
   pq.push(3);

   std::vector<int> v = {1, 2, 3};

   auto result = accumulate(v.begin(), v.end(), 0,
                              // parentheses are needed here std::plus<>()
                                                  std::plus<>());
}
C++ 模板 STL 函子

评论

1赞 Nathan Pierson 2/25/2023
因为模板参数列表是在寻找类型,而函数参数列表是在查找对象。同样的原因,你不会写.std::max(7, int)

答:

4赞 Vlad from Moscow 2/25/2023 #1

std::priority_queue是具有类型模板参数的类模板。其专用化需要指定类型模板参数。并且是用作类型模板参数的类型。std::greater<>

另一方面,在算法中,您需要提供一个函数对象,例如 。std::greater<>()

1赞 463035818_is_not_an_ai 2/25/2023 #2

在这两种情况下,可调用对象的类型都是模板参数。对于 you 显式声明模板参数,类型。通过传递比较器的实例,使模板 arugment(可以推断出比较器的类型)。std::priority_queuestd::accumulate

使用 CTAD(类模板参数演绎),这种差异就不那么明显了。如果你愿意,你可以反过来说:

#include <numeric>
#include <queue>

int main() {
    std::priority_queue pq(std::greater<int>{},std::vector<int>{});
    
    std::vector<int> x;
    std::accumulate<std::vector<int>::iterator,int,std::greater<>>(x.begin(),x.end(),0,{});
}

在这里,我利用 CTAD 让构造函数推断传递给构造函数的参数的类型。然后,它相当不常见,但如果您愿意,您可以显式指定算法的临时参数。尽管您仍然需要传递默认构造的实例,因为二进制操作的默认值没有重载(可能有,它只是没有那么有用,因为通常您只想编写并推导出所有模板参数)。std::accumulatestd::accumulate(..)

评论

0赞 Mikhail 2/25/2023
哦,这个例子是有道理的。虽然头很痛