为什么我不能将两个不同的比较器传递给一个模板函数?

why can't i pass two different comparators to one template function?

本文关键字:一个 函数 不能 两个 为什么 比较器      更新时间:2023-10-16

我在这里绞尽脑汁了几个小时,但我仍然不明白为什么当我试图运行这段代码时我得到了一个错误。过了一段时间,我设法把它缩小到这个表达:

pastryPrice()

导致了这个问题—正如您所看到的,我试图为排序

的一个模板函数构建多个比较器
    struct dialingAreaComp{
    inline bool operator()(const Deliver *d1, const Deliver *d2)const {
        return d1->getDialingArea() < d2->getDialingArea();
    }
};
struct pastryPrice {
    inline bool operator()(const Pastry *p1, const Pastry *p2)const {
        return p1->getPrice() < p2->getPrice();
    }
};
template<class T>
void sortCollection(T& collection)
{
    if ( typeid (collection) == typeid(vector <Deliver*>))
    {
        sort(collection.begin(), collection.end(), dialingAreaComp());
        printCollection(collection);
    }
    else if (typeid (collection) == typeid(vector <Pastry*>))
    {
        sort(collection.begin(), collection.end(), pastryPrice());
        printCollection(collection);
    }
    else { cout << "WRONG!"; }
}

我得到了五个错误,都是一样的:

项目文件行抑制状态错误C2664 'bool Bakery::pastryPrice::operator ()(const Pastry *,const Pastry *) const':无法将参数1从'Deliver *'转换为'const Pastry *' Bakery c:program files (x86)microsoft visual studio 14.0vcincludexutility 809

还有一个

项目文件行抑制状态错误C2056非法表达式面包店c:program files (x86)microsoft visual studio 14.0vcincludexutility 809

当我去掉上面写的表达式时,代码工作得很好 -为什么我不能将两个不同的比较器传递给一个模板函数?

:

C2264是当试图向函数传递不兼容类型的形参时发生的编译错误。

但是交付函数工作,当我取下交付比较器时,糕点也编译了…那么什么是不相容类型呢?

你的问题是无论哪个分支被编译,两个分支都被编译。

我会用不同的方式处理这个问题。

template<class A, class B>
struct overload_t:A,B{
  using A::operator();
  using B::operator();
  overload_t(A a, B b):A(std::move(a)), B(std::move(b)){}
};
template<class A, class B>
overload_t<A,B> overload( A a, B b ){
  return {std::move(a),std::move(b)};
}

这允许我们重载两个函数对象或lambda。(可以添加完美转发,也可以添加变量…,但我保持它简单)。

现在我们简单地:

auto comp=overload(dialingAreaComp{}, pastryPrice{});
using std::begin; using std::end;
std::sort( begin(collection), end(collection), comp );

,编译器为我们选择正确的比较函数。当我在那里的时候也支持平面数组。

停止使用using namespace std;


上面的代码所做的是将两个函数对象类型合并为一个。using A::operator()using B::operator()()移动到同一个类中,并告诉c++在使用通常的方法调用重载规则调用时在它们之间进行选择。其余的代码用于推断被重载的类型并移动构造它们。

sort用编译时根据容器类型确定的类型的对象调用()。重载解析(在调用点的sort内)然后在编译时选择正确的体进行比较。

因此,技术可以扩展为支持2个以上的重载、函数指针和转发引用。在c++ 17中,可以做一些工作来让重载类型推断出它的父类型,从而不需要工厂函数。

您会得到一个错误,因为模板化的函数是在编译时求值的,并且其中一个函数调用永远不会匹配。用简单的函数重载代替模板:

void sortCollection(vector <Deliver*>& collection)
{
    sort(collection.begin(), collection.end(), dialingAreaComp());
    printCollection(collection);
}
void sortCollection(vector <Pastry*>& collection)
{
    sort(collection.begin(), collection.end(), pastryPrice());
    printCollection(collection);
}