考虑这个存储价值和时间的简单类。
class A
{
public:
boost::posix_time::ptime when;
double value;
};
根据具体情况,我需要按值或按时间比较A
的两个实例(和/或将它们存储在set
/ map
中,有时按值排序,有时会按值排序按时间)。
提供operator<
会让您感到困惑,因为您无法判断它是按价值还是按时间进行比较。
现在,什么是最好的策略?
operator<
参数? (将用作a <(ByTime) b
)?lowerThan
(比较值)方法和earlierThan
(比较时间)方法,将右操作数作为参数吗?但那么,处理<
,<=
,>
,>=
,==
,!=
的最佳做法是什么?每个比较器的一种方法?或者他们可以采取参数(例如bool isLower(bool strict, const A& right) const
,bool isGreater(bool strict, const A& right) const
,bool isEarlier(bool strict, const A& right) const
,bool isLater(bool strict, const A& right) const
...... 最佳做法是什么?
答案 0 :(得分:1)
恕我直言,最通用的方式是两个步骤:
制作ADL吸气剂。
根据这些吸气剂编写比较概念。
示例:
#include <boost/date_time.hpp>
#include <set>
#include <vector>
#include <algorithm>
class A
{
public:
boost::posix_time::ptime when;
double value;
};
// get the 'when' from an A
auto get_when(A const& a) -> boost::posix_time::ptime
{
return a.when;
}
// get the 'when' from a ptime (you could put this in the boost::posix_time namespace for easy ADL
auto get_when(boost::posix_time::ptime t) -> boost::posix_time::ptime
{
return t;
}
// same for the concept of a 'value'
auto get_value(A const& a) -> double
{
return a.value;
}
auto get_value(double t) -> double
{
return t;
}
// compare any two objects by calling get_when() on them
struct increasing_when
{
template<class L, class R>
bool operator()(L&& l, R&& r) const
{
return get_when(l) < get_when(r);
}
};
// compare any two objects by calling get_value() on them
struct increasing_value
{
template<class L, class R>
bool operator()(L&& l, R&& r) const
{
return get_value(l) < get_value(r);
}
};
void example1(std::vector<A>& as)
{
// sort by increasing when
std::sort(begin(as), end(as), increasing_when());
// sort by increasing value
std::sort(begin(as), end(as), increasing_value());
}
int main()
{
// same for associative collections
std::set<A, increasing_when> a1;
std::set<A, increasing_value> a2;
}
更新
如果您愿意,可以进行比较:
template<class Comp>
struct compare_when
{
template<class L, class R>
bool operator()(L&& l, R&& r) const
{
return comp(get_when(l), get_when(r));
}
Comp comp;
};
using increasing_when = compare_when<std::less<>>;
using decreasing_when = compare_when<std::greater<>>;
直接在代码中使用比较:
auto comp = compare_when<std::greater<>>();
if (comp(x,y)) { ... }
答案 1 :(得分:1)
对UKMonkey的评论作出反应,将我理解的内容定义为“比较类”是一种很好的方法/实践吗?
class A
{
public:
boost::posix_time::ptime when;
double value;
const boost::posix_time::ptime& getTime() const { return when; }
double getValue() const { return value; }
};
template <typename T>
class CompareBy
{
public:
CompareBy( const A& a, T (A::*getter)() const ) : a(a), getter(getter)
{}
bool operator<( const CompareBy& right ) const
{
return (a.*getter)() < (right.a.*getter)();
}
// you may also declare >, <=, >=, ==, != operators here
private:
const A& a;
T (A::*getter)() const;
};
class CompareByTime : public CompareBy<const boost::posix_time::ptime&>
{
public:
CompareByTime(const A& a) : CompareBy(a, &A::getTime)
{
}
};
class CompareByValue : public CompareBy<double>
{
public:
CompareByValue( const A& a ) : CompareBy(a, &A::getValue)
{
}
};
struct byTime_compare {
bool operator() (const A& lhs, const A& rhs) const {
return CompareByTime(lhs) < CompareByTime(rhs);
}
};
int main()
{
A a, b;
...
if (CompareByValue(a) < CompareByValue(b))
{
...
}
std::set<A, byTime_compare> mySet;
}
答案 2 :(得分:0)
这里使用构造/销毁顺序很快完成(类似的实现到一个简单的锁而不考虑线程安全性):
比较看起来像:
Thing::thingSortingMode(Thing::thingSortingMode::alternateMode), Thing{1, 2} < Thing{3, 4};
在线运行此示例:http://cpp.sh/3ggrq
#include <iostream>
struct Thing {
struct thingSortingMode {
enum mode {
defaultMode,
alternateMode
};
mode myLastMode;
thingSortingMode(mode aMode) { myLastMode = Thing::ourSortingMode; Thing::ourSortingMode = aMode; std::cout << "\nmode: " << aMode << "\n"; }
~thingSortingMode() { Thing::ourSortingMode = myLastMode; std::cout << "\nmode: " << myLastMode << "\n";}
};
bool operator < (Thing another) {
switch (ourSortingMode) //I use an enum, to make the example more accessible, you can use a functor instead if you want
{
case thingSortingMode::alternateMode:
return myValueB < another.myValueB;
break;
default:
return myValueA < another.myValueA;
break;
}
}
static thingSortingMode::mode ourSortingMode;
int myValueA;
int myValueB;
};
Thing::thingSortingMode::mode Thing::ourSortingMode = Thing::thingSortingMode::defaultMode;
int main()
{
Thing a{1, 1}, b{0, 2}; // b < a in default mode, a < b in alternate mode
std::cout << (a < b); //false
{
Thing::thingSortingMode ctx(Thing::thingSortingMode::alternateMode);
std::cout << (a < b); //true
Thing::thingSortingMode(Thing::thingSortingMode::defaultMode), std::cout << (a < b), //false
Thing::thingSortingMode(Thing::thingSortingMode::alternateMode), std::cout << (a < b); //true
std::cout << (a < b); //true
}
std::cout << (a < b); //false
}
请注意,这个构造/破坏技巧可以管理任何类型的上下文状态,这里有一个更丰富的例子,有4个状态和更多嵌套的上下文
在线运行此示例:http://cpp.sh/2x5rj
#include <iostream>
struct Thing {
struct thingSortingMode {
enum mode {
defaultMode = 1,
alternateMode,
mode3,
mode4,
};
mode myLastMode;
thingSortingMode(mode aMode) { myLastMode = Thing::ourSortingMode; Thing::ourSortingMode = aMode; std::cout << "\nmode: " << myLastMode << " -> " << aMode << "\n"; }
~thingSortingMode() { std::cout << "\nmode: " << Thing::ourSortingMode << " -> " << myLastMode << "\n"; Thing::ourSortingMode = myLastMode; }
};
static thingSortingMode::mode ourSortingMode;
};
Thing::thingSortingMode::mode Thing::ourSortingMode = Thing::thingSortingMode::defaultMode;
int main()
{
Thing::thingSortingMode ctx(Thing::thingSortingMode::mode3);
{
Thing::thingSortingMode ctx(Thing::thingSortingMode::alternateMode);
{
Thing::thingSortingMode ctx(Thing::thingSortingMode::mode4);
{
Thing::thingSortingMode ctx(Thing::thingSortingMode::defaultMode);
std::cout << "end sub 3 (mode 1)\n";
}
std::cout <<
(Thing::thingSortingMode(Thing::thingSortingMode::alternateMode), "this is the kind of things that might behave strangely\n") <<
(Thing::thingSortingMode(Thing::thingSortingMode::defaultMode), "here both are printed in mode 2, but it's a direct consequence of the order in which this expression is evaluated\n"); //note though that arguments are still constructed in the right state
std::cout << "end sub 2 (mode 4). Not that we still pop our states in the right order, even if we screwed up the previous line\n";
}
std::cout <<
(Thing::thingSortingMode(Thing::thingSortingMode::alternateMode), "this on the other hand (mode 2)\n"),
std::cout <<
(Thing::thingSortingMode(Thing::thingSortingMode::defaultMode), "works (mode 1)\n"); //but pay attention to the comma and in which order things are deleted
std::cout << "end sub 1 (mode 2)\n";
}
std::cout << "end main (mode 3)\n";
}
输出:
mode: 1 -> 3
mode: 3 -> 2
mode: 2 -> 4
mode: 4 -> 1
end sub 3 (mode 1)
mode: 1 -> 4
mode: 4 -> 1
mode: 1 -> 2
this is the kind of things that might behave strangely
here both are printed in mode 2, but it's a direct consequence of the order in which this expression is evaluated
mode: 2 -> 1
mode: 1 -> 4
end sub 2 (mode 4). Not that we still pop our states in the right order, even if we screwed up the previous line
mode: 4 -> 2
mode: 2 -> 2
this on the other hand (mode 2)
mode: 2 -> 1
works (mode 1)
mode: 1 -> 2
mode: 2 -> 2
end sub 1 (mode 2)
mode: 2 -> 3
end main (mode 3)
mode: 3 -> 1
答案 3 :(得分:0)
另一种方法,非常简单:将模板比较器函数添加到A类使得最终可以轻松进行比较,并且非常容易出错:
#include <iostream>
#include <set>
using namespace std;
class A
{
public:
int when;
double value;
int getTime() const { return when; }
double getValue() const { return value; }
template<typename T>
bool isLower( T (A::*getter)() const,
bool strict,
const A& right ) const
{
if ( strict )
return ((*this).*getter)() < (right.*getter)();
else
return ((*this).*getter)() <= (right.*getter)();
}
template<typename T>
bool isGreater( T (A::*getter)() const,
bool strict,
const A& right ) const
{
if ( strict )
return ((*this).*getter)() > (right.*getter)();
else
return ((*this).*getter)() >= (right.*getter)();
}
template<typename T>
bool isEqual( T (A::*getter)() const,
const A& right ) const
{
return ((*this).*getter)() == (right.*getter)();
}
};
struct byTime_compare {
bool operator() (const A& lhs, const A& rhs) const {
return lhs.isLower( &A::getTime, true, rhs );
}
};
int main()
{
A a, b;
if ( a.isLower( &A::getValue, true, b ) ) // means a < b by value
{
// ...
}
std::set<A, byTime_compare> mySet;
}