Comparator
用于比较两个 unsigned long long
数字。DefaultComparator
支持默认的相等运算。CoarseGrainedComparator
支持
某种科斯粒度相等运算,例如,如果两个数字的绝对值在 1 之间,则它们被视为相等。struct Comparator {
virtual ~Comparator() = default;
virtual bool operator()(unsigned long long lhs, unsigned long long rhs) const = 0;
};
struct DefaultComparator : public Comparator {
bool operator()(unsigned long long lhs, unsigned long long rhs) const override {
return lhs == rhs;
}
};
struct CoarseGrainedComparator : public Comparator {
bool operator()(unsigned long long lhs, unsigned long long rhs) const override {
static constexpr T kThres = 1;
if (lhs < rhs) {
return (rhs - lhs) <= kThres;
} else {
return (lhs - rhs) <= kThres;
}
}
};
我之所以采用OO编程方式,是因为我想将它们保存在一个哈希图中。所以,我需要一个通用类型,即
Comparator
。
using ComparatorPtr = std::shared_ptr<Comparator>;
template <typename ComparatorT>
ComparatorPtr ComparatorBuilder() {
return std::make_shared<ComparatorT>();
}
class CompatorFactory : public Singleton<CompatorFactory> {
public:
void Register(unsigned int slot, ComparatorPtr comparator) {
compators_.emplace(slot, comparator);
}
bool Get(unsigned int slot, ComparatorPtr& campator) {
auto it = compators_.find(slot);
if (it == compators_.end()) {
return false;
}
campator = it->second;
return true;
}
private:
std::unordered_map<unsigned int, ComparatorPtr> compators_;
};
客户端代码如下:
// Register the comparator for a specific slot id(301)
CompatorFactory::GetInstance()->Register(301, ComparatorBuilder<CoarseGrainedComparator>());
// Prepare old value and new value
// ......
// Compare old value and new value based on specific comparator.
ComparatorPtr comparator;
if (!CompatorFactory::GetInstance()->Get(slot_id, comparator)) {
comparator = ComparatorBuilder<DefaultComparator>();
}
auto equal = (*comparator)(old_value, new_value);
// Post operation based on equal
// ......
到目前为止,代码运行良好。
除了
unsigned long long
,还应该支持double
。
double
,但是会引入很多重复的代码。struct Comparator {
virtual ~Comparator() = default;
template <typename T>
virtual bool operator()(const T& lhs, const T& rhs) const = 0;
};
struct DefaultComparator : public Comparator {
template <typename T>
bool operator()(const T& lhs, const T& rhs) const override {
return lhs == rhs;
}
};
struct CoarseGrainedComparator : public Comparator {
template <typename T>
bool operator()(const T& lhs, const T& rhs) const override {
static constexpr T kThres = 1;
if (lhs < rhs) {
return (rhs - lhs) <= kThres;
} else {
return (lhs - rhs) <= kThres;
}
}
};
这导致了另一个问题:尝试将静态多态性与动态多态性混合是不可行的。
那么,我们如何解决这样的问题呢?
更好的解决方案可以混合静态电位和动态电位。
这个答案说明了如何使用类型擦除来模拟 C++ 中的“模板化虚拟”。它假设如下,
代码使用
std::any
进行类型擦除,但也可以使用其他形式的类型擦除。
#include <cassert>
#include <any>
//Table for all the fundamental operations that solely depend on static polymorphism and can be used as building blocks after type erasure
struct ComparatorFuncTable{
std::any (*from_int)(int);
bool (*eq)(const std::any&, const std::any&);
bool (*lt)(const std::any&, const std::any&);
bool (*le)(const std::any&, const std::any&);
std::any (*minus)(const std::any&, const std::any&);};
//C++14 variable template for the actual table
template <typename T>
ComparatorFuncTable comparatorFuncTable = {
.from_int = +[](int v){return std::any{static_cast<T>(v)};},
.eq = +[](const std::any& lhs, const std::any& rhs){return std::any_cast<T>(lhs) == std::any_cast<T>(rhs);},
.lt = +[](const std::any& lhs, const std::any& rhs){return std::any_cast<T>(lhs) < std::any_cast<T>(rhs);},
.le = +[](const std::any& lhs, const std::any& rhs){return std::any_cast<T>(lhs) <= std::any_cast<T>(rhs);},
.minus = +[](const std::any& lhs, const std::any& rhs){return std::any{T{std::any_cast<T>(lhs) - std::any_cast<T>(rhs)}};},
};
struct Comparator {
virtual ~Comparator() = default;
//While non-virtual by itself, call to run() performs the dynamic dispatch
template <typename T>
bool operator()(const T& lhs, const T& rhs) const {
return run(lhs, rhs, comparatorFuncTable<T>);
}
protected:
virtual bool run(const std::any& lhs, const std::any& rhs, const struct ComparatorFuncTable& table) const = 0;
};
struct DefaultComparator : public Comparator {
protected:
virtual bool run(const std::any& lhs, const std::any& rhs, const ComparatorFuncTable& table) const override {
return table.eq(lhs,rhs);
}
};
struct CoarseGrainedComparator : public Comparator {
protected:
virtual bool run(const std::any& lhs, const std::any& rhs, const ComparatorFuncTable& table) const override {
//Use the type erased operations to build the complex operation
std::any kThres = table.from_int(1);
if (table.lt(lhs, rhs)) {
return table.le(table.minus(rhs, lhs), kThres);
} else {
return table.le(table.minus(lhs, rhs), kThres);
}
}
};
int main(){
const Comparator& cmp1=DefaultComparator{};
const Comparator& cmp2=CoarseGrainedComparator{};
assert(cmp1(2.0, 2.0) && cmp2(2.0, 2.0));
assert(cmp1(2.0f, 2.0f) && cmp2(2.0f, 2.0f));
assert(!cmp1(2.0f, 2.5f) && cmp2(2.0f, 2.5f));
}