我正在学习C ++ STL。我知道如果要在使用STL算法或容器时完成自定义功能,可以使用functor或模板专用化。例如:
class my_class {
public:
int id;
int num;
};
// Definition of hash and comparison functor of my_class, which is so-called Explicit Template Specialization
namespace std {
template <>
struct hash<my_class> {
size_t operator()(const my_class& e) const
{
return hash<int>()(e.id);
}
};
template <>
struct equal_to<my_class> {
bool operator()(const my_class& le, const my_class& re) const
{
return le.id == re.id;
}
};
};
int main()
{
unordered_set<my_class> s;
s.insert(my_class{ 0, 10 });
s.insert(my_class{ 1, 30 });
s.insert(my_class{ 0, 20 });
s.insert(my_class{ 2, 40 });
for (auto e : s) {
cout << "Value of ID " << e.id << ": " << e.num << endl;
}
cout << "Size of set: " << s.size() << endl;
return 0;
}
但是如何使用STL排序对具有模板专业化功能的自定义类对象进行排序?
以下错误:
class my_class {
public:
int id;
int num;
};
namespace std {
template <>
struct comp<my_class> {
bool operator()(const my_class& le, const my_class& re) const
{
return le.id < re.id;
}
};
};
int main()
{
vector<my_class> v;
v.push_back(my_class{ 2, 10 });
v.push_back(my_class{ 3, 10 });
v.push_back(my_class{ 0, 10 });
v.push_back(my_class{ 1, 10 });
sort(v.begin(), v.end());
cout << "Vector after sorting:" << endl;
for (const auto& e : v) {
cout << "Value of ID " << e.id << ": " << e.num << endl;
}
return 0;
}
答案 0 :(得分:1)
例如,在比较std::less
中的键时考虑了std::map
,std::sort
的默认行为是使用operator <
(重载#1 here)。专门化std::less
仍然有效,但是您需要像这样将其显式传递给std::sort
:
namespace std {
template <>
struct less<my_class> {
bool operator()(const my_class& le, const my_class& re) const
{
return le.id < re.id;
}
};
}
// Fill vector with my_class instances...
std::sort(v.begin(), v.end(), std::less<my_class>{});
请注意,这与在地图中插入项目有何不同:
// std::less<my_class> is used by default to compare key instances:
std::map<my_class, int> m;
m[{1, 1}] = 42;
答案 1 :(得分:1)
不能。这是sort(gcc 4.8.2)的源代码:
/**
* @brief Sort the elements of a sequence.
* @ingroup sorting_algorithms
* @param __first An iterator.
* @param __last Another iterator.
* @return Nothing.
*
* Sorts the elements in the range @p [__first,__last) in ascending order,
* such that for each iterator @e i in the range @p [__first,__last-1),
* *(i+1)<*i is false.
*
* The relative ordering of equivalent elements is not preserved, use
* @p stable_sort() if this is needed.
*/
template<typename _RandomAccessIterator>
inline void
sort(_RandomAccessIterator __first, _RandomAccessIterator __last)
{
typedef typename iterator_traits<_RandomAccessIterator>::value_type
_ValueType;
// concept requirements
__glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
_RandomAccessIterator>)
__glibcxx_function_requires(_LessThanComparableConcept<_ValueType>)
__glibcxx_requires_valid_range(__first, __last);
if (__first != __last)
{
std::__introsort_loop(__first, __last,
std::__lg(__last - __first) * 2);
std::__final_insertion_sort(__first, __last);
}
}
/**
* @brief Sort the elements of a sequence using a predicate for comparison.
* @ingroup sorting_algorithms
* @param __first An iterator.
* @param __last Another iterator.
* @param __comp A comparison functor.
* @return Nothing.
*
* Sorts the elements in the range @p [__first,__last) in ascending order,
* such that @p __comp(*(i+1),*i) is false for every iterator @e i in the
* range @p [__first,__last-1).
*
* The relative ordering of equivalent elements is not preserved, use
* @p stable_sort() if this is needed.
*/
template<typename _RandomAccessIterator, typename _Compare>
inline void
sort(_RandomAccessIterator __first, _RandomAccessIterator __last,
_Compare __comp)
{
typedef typename iterator_traits<_RandomAccessIterator>::value_type
_ValueType;
// concept requirements
__glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
_RandomAccessIterator>)
__glibcxx_function_requires(_BinaryPredicateConcept<_Compare, _ValueType,
_ValueType>)
__glibcxx_requires_valid_range(__first, __last);
if (__first != __last)
{
std::__introsort_loop(__first, __last,
std::__lg(__last - __first) * 2, __comp);
std::__final_insertion_sort(__first, __last, __comp);
}
}
在实现中
void sort(_RandomAccessIterator __first, _RandomAccessIterator __last)
没有比较功能,因此您无法通过模板专门化对其进行自定义。您必须使用
void sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp)
答案 2 :(得分:0)
您无需专门研究std::equal_to
或std::less
,只需提供operator ==
和operator <
,以便可以从不合格的呼叫中找到它们。
您专门研究std::hash
,因为没有operator hash
。
bool operator ==(const my_class& le, const my_class& re) const
{
return le.id == re.id;
}
bool operator <(const my_class& le, const my_class& re) const
{
return le.id < re.id;
}
提供了这些功能之后,就这些而言,为!=
,>
<=
和>=
提供重载也很有用。您可以明确地做到这一点,或从boost::totally_ordered
class my_class : public boost::totally_ordered<my_class> {
public:
int id;
int num;
};
我知道我是否想在使用STL时完成自定义功能 算法或容器,我可以使用函子或模板专业化。
不一定。该语言以多种方式提供定制点。其中一些是按函子,某些是通过模板专门化,在这种情况下,是通过providing an overload来实现运算符功能。