静态模板类的建议

时间:2011-07-19 08:34:20

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

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

我需要一个处理这个的类,有一些方法可以说给出一个值,它所属的分区的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. 其他/建议?
  5. 编辑:

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

    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));
    }
    

3 个答案:

答案 0 :(得分:4)

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

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

最后,您可以实例化模板,将常量传递给它:

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

答案 1 :(得分:2)

你考虑过一个特质课吗?通常,如果您希望将静态信息与类中的行为分开,则可以考虑创建一个封装它的traits类。

所以我从默认行为开始:

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
};

答案 2 :(得分:0)

查看find_ifbind2nd以及仿函数的用法,似乎您对STL和一些高级C ++概念非常了解;然而,你想要做的似乎是过度工程。虽然我无法完全理解你想要做什么,但似乎你可以完全取消模板并只使用一个类(用不同的值实例化)和方法参数。