【问题标题】:advice for static template class静态模板类的建议
【发布时间】:2023-03-18 19:24:01
【问题描述】:

我有这个问题(直方图)。我有一个真实的空间:[a,b] 以某种方式分区 ([a0=a, a1, a2, ..., b])。分区可以是相等的空间 (a1 - a0 = a2 - a1 = ...) 或变量。

我需要一个类来处理这个问题,并通过一些方法说给定它所属分区的 bin 的值;查找特定 bin 中心的其他方法等等。

在程序中我不喜欢实例化一个类只调用这些简单的函数像

Binner binner(binning);
binner.get_bin(1.3);
binner.get_centerbin(2);

所以我尝试使用模板编写一个静态类来做类似的事情:

Binner<binning>::get_bin(1.3);
Binner<binning>::get_centerbin(2);

这是个好主意吗?还有其他方法吗?现在我有免费的功能,比如

double get_bin(double bin, Binning binning); // a lot of if/else inside

但我认为这太容易出错了。

这是我的实现:

enum Binning {CELL, LARGE, BE};
const double binning_LARGE[] = {0, 1.2, 1.425, 1.550, 1.800, 2.5};
const double binning_BE[] =  {0, 1.425, 1.550, 2.5};

template<Binning binning>
class Binner
{
public:
    static const double* bins;
    static const int n;
    static int get_bin(double value);
};

template<> const double* myclass<LARGE>::bins = binning_LARGE;
template<> const double* myclass<BE>::bins = binning_BE;

template<> const int myclass<LARGE>::n = sizeof(binning_LARGE) / sizeof(double);
template<> const int myclass<BE>::n = sizeof(binning_BE) / sizeof(double);

template<Binning binning> int myclass<binning>::get_bin(double value)
{
    return find_if(bins, bins + n,
           bind2nd(greater<double>(), value)) - bins - 1;
}

template<> int myclass<CELL>::get_bin(double value)
{
    return static_cast<int>(value / 0.025);
}
  1. 这是一个好的实现/设计吗?
  2. 有没有办法避免使用n 字段使用std::vector?怎么样?
  3. 有没有办法对0.025 进行参数化?我知道double 不能是模板参数,但我可以写类似这样的东西吗:

    Binner<0.025> binner;
    
  4. 其他/建议?

编辑:

第三点为什么我不能这样做:

template<Binning binning, int N=100>
class Binner
{
public:
    static const double* bins;
    static const int n;
    static int bin(double value);
};

...

template<Binning binning, int N> int Binner<CELL, N>::bin(double value)
{
    return static_cast<int>(value / (2.5 / N));
}

【问题讨论】:

  • +1,不知道double不能是template参数。
  • 看起来很好地展示了模板的使用。但我感觉你所做的一切都可以通过选择合适的 STL 容器并定义所需的方法来实现。

标签: c++ templates static histogram static-polymorphism


【解决方案1】:

恕我直言,如果您不想实例化一个类,您的设计还可以。确实,这对我来说似乎是一种template metaprogramming。这是否有意义取决于您计划如何重用此模板。

当然,使用 std::vector 可以让您摆脱变量来保存数组大小。现在,如果这对您的设计有好处,我不知道...它会将一些复杂性从您的模板定义移到分箱定义中(现在您可以非常简单地对其进行初始化)...

最后,你可以实例化你的模板,传递一个常量给它:

template < Binning binning, unsigned long N, unsigned long M>
class ... {
     <using N>
}

【讨论】:

  • +1,我也觉得这个设计不错。但没有足够的信心说出来。
  • 什么是N?是N = 2.5 / 0.025(就我而言)?
  • 我认为它是你想摆脱的常数;它应该很长,比如 25,所以要么将其除以 1000,要么在模板声明中定义 2 个这样的长常量...
  • 我不能用不同的模板参数重新声明我的模板类。现在是Binning,我需要它。一种解决方案是对可变大小的分箱使用负枚举值,对等空间分箱使用正的枚举值。
  • 怎么样:template &lt;Binning binning, unsigned long N, unsigned long M&gt;?
【解决方案2】:

你考虑过特质类吗?通常,如果您想要将静态信息与类中的行为分开,您可能会考虑创建一个封装它的特征类。

所以我会从默认行为开始:

enum Binning {CELL, LARGE, BE};

template <Binning binning>
struct BinTraits
{
    // default behaviour
    int get_bin(double value) { return value / 0.025; } 
};

然后我会提供专业:

const double binning_LARGE[] = {0, 1.2, 1.425, 1.550, 1.800, 2.5};
const double binning_BE[] =  {0, 1.425, 1.550, 2.5};

template <typename RandomAccessCollectionT>
int get_bin_impl(double value, RandomAccessCollectionT collection, unsigned size)
{
    return find_if(collection, collection + size,
           bind2nd(greater<double>(), value)) - collection - 1;
}

template <>
struct BinTraits<LARGE>
{
    int get_bin(double value) { return get_bin_impl(value, binning_LARGE, sizeof(binning_LARGE) / sizeof(binning_LARGE[0])); } 
};

template <>
struct BinTraits<BE>
{
    int get_bin(double value) { return get_bin_impl(value, binning_BE, sizeof(binning_BE) / sizeof(binning_BE[0])); } 
};

然后我会将实际的容器行为放在另一个需要分箱行为的类中(我们称之为HashTable):

template <typename BinTraits>
class HashTable
{
public:
    void insert(double value)
    {
        int bin = BinTraits::get_bin(value);
        _bins[bin].insert(value);
    }
    // _bin is a multimap or something
};

【讨论】:

  • 你的解决方案很好,但我同意 Jaywalker 的观点:我们过度设计了。
【解决方案3】:

看看find_if和bind2nd以及仿函数的用法,你好像对STL和一些高级C++概念很了解;然而,你试图做的似乎是过度设计。虽然我不能完全理解您要做什么,但似乎您可以完全取消模板并只使用一个类(用不同的值实例化)和方法参数。

【讨论】:

    猜你喜欢
    • 2015-04-04
    • 2019-05-10
    • 1970-01-01
    • 1970-01-01
    • 2012-03-02
    • 1970-01-01
    • 2017-10-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多