为什么我不能将两个不同的比较器传递给一个模板函数?
why can't i pass two different comparators to one template function?
我在这里绞尽脑汁好几个小时,但我仍然不明白为什么在尝试 运行 这段代码时会出现错误。
一段时间后,我设法将其缩小为表达式:
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!"; }
}
我收到五个错误,都是一样的:
Severity Code Description Project File Line Suppression State
Error C2664 'bool Bakery::pastryPrice::operator ()(const Pastry *,const Pastry *) const': cannot convert argument 1 from 'Deliver *' to 'const Pastry *' Bakery c:\program files (x86)\microsoft visual studio 14.0\vc\include\xutility 809
还有一个:
Severity Code Description Project File Line Suppression State
Error C2056 illegal expression Bakery c:\program files (x86)\microsoft visual studio 14.0\vc\include\xutility 809
当我去掉上面写的表达式时,代码工作正常很好 - 为什么我不能将两个不同的比较器传递给一个模板函数?
现在:
C2264 is a Compiler Error that occurs when one tries to pass a function a parameter of an incompatible type.
但是 Deliver 功能有效,当我取消 Deliver 比较器时,Pastry 也编译了...那么不兼容的类型是什么?
您收到错误消息是因为模板函数是在编译时求值的,其中一个函数调用永远不会匹配。使用简单的函数重载代替模板:
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);
}
你的问题是无论选择哪一个分支都会编译。
我会采用不同的方法。
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()
将两个 ()
移动到相同的 class 并告诉 C++ 在使用通常的方法调用重载规则调用时在它们之间进行选择。其余代码是胶水,用于推断被重载的类型并移动构造它们。
sort
使用编译时根据容器类型确定类型的对象调用 ()
。重载解析(在调用点 sort
内)然后选择正确的主体在编译时进行比较。
因此,可以通过支持 2 个以上的重载、函数指针和转发引用来扩展技术。在 C++17 中,可以做一些工作让重载类型推导其父类型,从而消除对工厂函数的需要。
我在这里绞尽脑汁好几个小时,但我仍然不明白为什么在尝试 运行 这段代码时会出现错误。 一段时间后,我设法将其缩小为表达式:
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!"; }
}
我收到五个错误,都是一样的:
Severity Code Description Project File Line Suppression State Error C2664 'bool Bakery::pastryPrice::operator ()(const Pastry *,const Pastry *) const': cannot convert argument 1 from 'Deliver *' to 'const Pastry *' Bakery c:\program files (x86)\microsoft visual studio 14.0\vc\include\xutility 809
还有一个:
Severity Code Description Project File Line Suppression State Error C2056 illegal expression Bakery c:\program files (x86)\microsoft visual studio 14.0\vc\include\xutility 809
当我去掉上面写的表达式时,代码工作正常很好 - 为什么我不能将两个不同的比较器传递给一个模板函数?
现在:
C2264 is a Compiler Error that occurs when one tries to pass a function a parameter of an incompatible type.
但是 Deliver 功能有效,当我取消 Deliver 比较器时,Pastry 也编译了...那么不兼容的类型是什么?
您收到错误消息是因为模板函数是在编译时求值的,其中一个函数调用永远不会匹配。使用简单的函数重载代替模板:
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);
}
你的问题是无论选择哪一个分支都会编译。
我会采用不同的方法。
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()
将两个 ()
移动到相同的 class 并告诉 C++ 在使用通常的方法调用重载规则调用时在它们之间进行选择。其余代码是胶水,用于推断被重载的类型并移动构造它们。
sort
使用编译时根据容器类型确定类型的对象调用 ()
。重载解析(在调用点 sort
内)然后选择正确的主体在编译时进行比较。
因此,可以通过支持 2 个以上的重载、函数指针和转发引用来扩展技术。在 C++17 中,可以做一些工作让重载类型推导其父类型,从而消除对工厂函数的需要。