Я думаю, что вы должны просто поместить только общие части в третью функцию, оставляя dense_histogram
и sparse_histogram
для создания h
и вызывать эту функцию реализации:
template <class V, class C = size_t, class H>
inline void histogram_impl(const V & x, H& h) {
typedef typename V::value_type E; // element type
C bmax = 0; // bin max
for_each(begin(x), end(x), // C++11
[&h, &bmax] (const E & e) { // value element
h[e]++;
bmax = std::max(bmax, h[e]);
});
return h;
}
template <class V, class C = size_t, class H = vector<C> >
inline H dense_histogram(const V & x) {
typedef typename V::value_type E; // element type
size_t n = (static_cast<C>(1)) << (8*sizeof(E)); // maximum number of possible elements for dense variant
H h(n, 0); // histogram
histogram_impl(x, h);
return h;
}
template <class V, class C = size_t, class H = unordered_map<typename V::value_type, C> >
inline H sparse_histogram(const V & x) {
H h; // histogram
histogram_impl(x, h);
return h;
}
Однако, поскольку вы запросилиit: Поскольку вы работаете с контейнерами, я бы предположил, что у них дешевый ход, так что вы можете определить черту создания для генерации вашего контейнера и переместить ее в локальную переменную.Затем вы можете написать собственное обнаружение соответствующего конструктора, например:
template<typename T> struct has_explicit_length_constructor{
private:
template<typename U>
decltype(U(0, 0), void(), std::true_type()) test(int x);
template<typename>
std::false_type test(...);
typedef decltype(test<T>(0)) constant_type;
public:
constexpr bool value = constant_type::value;
};
template<class H, bool B = has_explicit_length_constructor<H>::value> struct histogram_creation_trait;
template<class H> struct histogram_creation_trait<H, true> {
static H create() {
size_t n = (static_cast<C>(1)) << (8*sizeof(typename V::value_type));
return H(n, 0);
}
};
template<class H> struct histogram_creation_trait<H, false>
{ static H create() { return H(); } };
template <class V, class C = size_t, class Ht>
inline void histogram_impl(const V & x, H& h, Trait) {
typedef typename V::value_type E; // element type
C bmax = 0; // bin max
H h = histogram_creation_trait<H>::create();
for_each(begin(x), end(x), // C++11
[&h, &bmax] (const E & e) { // value element
h[e]++;
bmax = std::max(bmax, h[e]);
});
return h;
}
template <class V, class H = vector<size_t> > H make_dense_histogram(const V & x) { return histogram_impl<V, size_t, H>(x); }
template <class V, class H = unordered_map<typename V::value_type, size_t> > H make_sparse_histogram(const V & x) { return histogram_impl<V, size_t, H>(x); }
В качестве стороны, не являющейся стороной: добавление ваших собственных методов к std
- это UB по стандарту ([namespace.std] $17.6.4.2.1 p1
):
Поведение программы на C ++ не определено, если она добавляет объявления или определения в пространство имен std или в пространство имен в пространстве имен std, если не указано иное.Программа может добавить специализацию шаблона для любого шаблона стандартной библиотеки в пространство имен std, только если объявление зависит от типа, определенного пользователем, и специализация соответствует требованиям стандартной библиотеки для исходного шаблона и явно не запрещена.