考虑结构:
onFirst
是否可以将方法onSecond
和compBLess
重构为一个简单的方法而又不影响代码可维护性?请注意,不能使用compBGreater
/ comp
代替 template<typename TSet>
void onBoth(int val){
TSet* set;
if ( std::is_same<TSet, decltype(m_setLess)>::value ) {
set = reinterpret_cast<TSet*>(&m_setLess);
} else {
set = reinterpret_cast<TSet*>(&m_setGreater);
}
auto i_set = set->begin();
std::function<bool()> comp;
if( std::is_same<TSet, decltype(m_setLess)>::value )
comp = std::function<bool()>([&]() { return val >= i_set->b1; });
else
comp = std::function<bool()>([&]() { return val <= i_set->b1; });
while ( i_set != set->end() && comp() ) {
sameForBoth(*i_set);
++i_set;
}
}
。
我对这个问题的看法:
reinterpret_cast<>
但是我的解决方案似乎太复杂了。另外,我不确定以这种方式使用replace()
是否是一个好习惯。
还有其他方法吗?
答案 0 :(得分:2)
如果我正确理解这一点,似乎您想对碰巧满足comp
一元谓词的每个元素应用一个操作。因此,我们可以线性扫描元素并应用函数,直到给定谓词成立为止。
由于您正在研究范围,因此可能的方法是设计通用过程,如下所示:
template <typename I, typename P, typename F>
// I models InputIterator
// P models UnaryPredicate
// F models UnaryFunction
// Domain<P> == ValueType<I>
// Domain<F> == ValueType<I>
void apply_until(I first, I last, P p, F f) {
while (first != last) {
if (!p(*first)) return;
f(*first);
++first;
}
}
我们可以使用这种通用算法,例如打印出严格小于3
的范围内的值:
int main() {
std::set<int> s1 = {1, 2, 3, 4, 5};
apply_until(s1.begin(), s1.end(), [](int x) { return x < 3;}, [](int x) { std::cout << x << '\n'; });
}
我会保留onFirst
和onSecond
之间的区别,因为它们是要在不同的集合上运行。用例的代码可能减少为:
void onFirst(int val) {
apply_until(m_setLess.begin(), m_setLess.end(), [&](B const& x) { return x.b1 >= val; }, [&](B const& x) { sameForBoth(x); });
}
void onSecond(int val) {
apply_until(m_setGreater.begin(), m_setGreater.end(), [&](B const& x) { return x.b1 <= val; }, [&](B const& x) { sameForBoth(x); });
}
答案 1 :(得分:1)
在这两个函数中,我们都在一个范围内进行迭代,从std::set
的开始一直到取决于输入值的给定迭代器。
在这个答案中,我假设compBLess
和compBGreater
的定义是这样的(重要的部分是b1字段比b2字段占主导地位。最后请看稍有不同的内容版本)
struct compBLess {
bool operator ()(B const & o1, B const& o2) const {
return std::make_pair(o1.b1,o1.b2) < std::make_pair(o2.b1,o2.b2);
}
};
struct compBGreater {
bool operator ()(B const & o1, B const& o2) const {
return std::make_pair(o1.b1,o1.b2) > std::make_pair(o2.b1,o2.b2);
}
};
在这种假设下,我认为惯用的方法是使用lowerbound, upperbound methods of std::set查找迭代的结束,然后使用
template<typename Iterator>
void foo(Iterator it, Iterator end) {
std::for_each(it,end,[this](auto & o){ sameForBoth(o); });
}
这将在性能上更加有效,因为我们将进行O(log(size_of_set))比较(使用下限/上限),而不是O(size_of_set)比较(在循环中使用comp
)>
其他方法的实际实现如下:
void onFirst(int val) {
foo(m_setLess.begin(), m_setLess.lowerbound({val,std::numeric_limits<int>::min}));
}
void onSecond(int val) {
foo(m_setGreater.begin(), m_setGreater.upperbound({val-1,std::numeric_limits<int>::max}));
}
编辑:在@ z3dd的评论之后,以下是适用于稍有不同的compBLess
和compBGreater
(与b2
字段的顺序相反)的实现:
struct compBLess {
bool operator ()(B const & o1, B const& o2) const {
return std::make_pair(o1.b1,-o1.b2) < std::make_pair(o2.b1,-o2.b2);
}
};
struct compBGreater {
bool operator ()(B const & o1, B const& o2) const {
return std::make_pair(o1.b1,-o1.b2) > std::make_pair(o2.b1,-o2.b2);
}
};
void onFirst(int val) {
foo(m_setLess.begin(), m_setLess.lowerbound({val,std::numeric_limits<int>::max}));
}
void onSecond(int val) {
foo(m_setGreater.begin(), m_setGreater.upperbound({val-1,std::numeric_limits<int>::min}));
}
[请注意,如果compBLess
和compBGreater
的实现方式与给定的2种实现方式中的任何一种都不一样,则@Ilio Catallo的答案就是一种可以使用的方式。]