我在这里唠叨了几个小时,但我仍然不明白为什么我在尝试运行此代码时遇到错误。 过了一段时间,我设法将其缩小到表达式:
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.0 \ vc \ include \ xutility 809
还有一个:
严重级代码描述项目文件行抑制状态 错误C2056非法表达面包店c:\ program files(x86)\ microsoft visual studio 14.0 \ vc \ include \ xutility 809
当我取消上面写的表达式时,代码工作很好 - 为什么我不能将两个不同的比较器传递给一个模板函数?
现在:
C2264是一个编译器错误,当一个人试图传递一个不兼容类型的参数时会发生。
但Deliver功能正常工作,当我取下Pasiver编译的Deliver比较器时...那么什么是不兼容的类型?
答案 0 :(得分:5)
你的问题是两个分支都被编译,无论采取哪一个分支。
我会采用不同的方法。
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)};
}
这让我们重载两个函数对象或lambdas。 (可以添加完美的转发,varargs ......,但我保持简单)。
现在我们只是:
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中,可以做一些工作来让重载类型推导出它的父类型,从而不再需要工厂函数。
答案 1 :(得分:4)
您收到错误,因为模板化函数在编译时被计算,其中一个函数调用永远不会匹配。而不是模板使用简单的函数重载:
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);
}