这是一个C++ 14的答案。一切都可以转换为C++ 11,只是不太漂亮。
template<class F, class Base=std::less<>>
auto order_by(F&& f, Base&& b={}) {
return
[f=std::forward<F>(f), b = std::forward<Base>(b)]
(auto const& lhs, auto const& rhs)
->bool
{
return b(f(lhs), f(rhs));
};
}
order_by
需要投影和任选的比较函数对象,并返回然后应用投影要么std::less<>
或比较功能对象的比较功能对象。
这对排序或搜索很有用,因为C++算法需要比较函数对象,而投影很容易编写。
template<class A, class B>
struct binary_overload_t:A,B{
using A::operator();
using B::operator();
binary_overload_t(A a, B b):A(std::move(a)), B(std::move(b)) {}
};
template<class A, class B>
binary_overload_t< A, B >
binary_overload(A a, B b) {
return { std::move(a), std::move(b) };
}
binary_overload
让你重载函数对象。
template<class T>
struct valid_range_t {
T start, finish;
};
这代表有效范围。我可以使用std::pair
,但我更喜欢带有含义的类型。
template<class T, class V>
struct ranged_value_t {
valid_range_t<T> range;
V value;
};
template<class T, class It>
auto find_value(It begin, It end, T const& target)
-> decltype(std::addressof(begin->value))
{
// project target into target
// and a ranged value onto the lower end of the range
auto projection = binary_overload(
[](auto const& ranged)->T const& {
return ranged.range.finish;
},
[](T const& t)->T const& {
return t;
}
);
//
auto it = std::upper_bound(begin, end,
target,
order_by(projection)
);
if (it == end) return nullptr;
if (target < it->range.start) return nullptr;
return std::addressof(it->value);
}
现在find_value
需要一对迭代到布置有非重叠范围ranged_value_t
型结构。
然后它返回一个指针,指向第一个(因此只有)值(其半开)范围包含target
的条目。
ranged_value_t<int, char> table[]={
{{0,40}, 'T'},
{{41,55}, 'D'},
{{56,70}, 'P'},
{{71,80}, 'A'},
{{81,90}, 'E'},
{{91,101}, 'O'}
};
auto* ptr = find_value(std::begin(table), std::end(table), 83);
if (ptr) std::cout << *ptr << "\n"; else std::cout << "nullptr\n";
Live example。
这个答案在替代的优点:
- 我们不创造价值不必要的对象。如果价值对象是昂贵的,大的或不平凡的可构建的,这就很重要。
- 创建表格的语法很简单
- 表格几乎可以采用任何格式。你可以从文件中解析它们;
find_value
函数只需要迭代器(并且更喜欢它们是随机访问)。
- 我们可以增加允许省略下限。我们必须添加一个标记
valid_range_t
(或使用一个可选项)并在find_value
中使用它,当我们检查s
时,并将构造函数添加到valid_range_t
以使其易于使用。
增广它同时支持半开放式和封闭式的时间间隔会采取一些工作。作为第二次检查,我会被诱惑入侵find_value
。
重叠间隔也需要一些工作。我会在开始时执行lower_bound(s
),并在结束时执行upper_bound(f
)。
我觉得这种东西最适合数据驱动设计;在C++代码中硬编码是一个糟糕的计划。相反,您需要使用配置,然后编写代码进行验证并由该配置驱动。
它是这个或查找表,只有6个记录,但这种方法似乎没问题。可能要重构幻数 –
您不必与下一个条件与前一个的否定。还有'else',它不需要在那里,因为有'return'。 – LogicStuff
@LogicStuff也许是为了清楚。 –