2011-10-07 59 views
1
之间选择

是否有可能实现以下使用模板说明的想法:C++模板:如何动态类和基本类型

// please excuse any syntax errors. 

template<typename KEY, typename VALUE> 
class Container { 
public: 
    VALUE calculate(vector<KEY> searchFors) 
    { 
     KEY searchFor = searchFors[0]; 
     pair<KEY,VALUE> lower = getLower(searchFor); 
     pair<KEY,VALUE> upper = getUpper(searchFor); 
     // calculateImpl uses + - */
     VALUE value = calculateImpl( 
      lower.first, lower.second(searchFor), 
      upper.first, upper.second(searchFor)); 
     return value; 
    } 
    // an example of calculateImpl 
    VALUE calculateImpl(KEY key1, VALUE value1, KEY key2, VALUE value2) 
    { 
     return value1 * value2; 
    } 
    // an example of getLower getUpper, assuming there're more than 2 elements in _data 
    pair<KEY,VALUE> getLower(KEY key) 
    { 
     return *(_data.begin()); 
    }   
    pair<KEY,VALUE> getUpper(KEY key) 
    { 
     return *(_data.begin()+1); 
    }   

private: 
    vector<pair<KEY,VALUE>> _data; 
}; 

注意,值需要操作的实现()。我如何使它可以在基元或函子之间进行选择?例如,如果searchFors.size()== 0,则将VALUE用作基元,否则,使用VALUE作为函子?

换言之,根据取决于矢量大小的开关,VALUE可能是原始类型(VALUE类型)或函子(VALUE类型(*)(KEY))。

这种容器的用法是

vector<double> keys; 
keys.push_back(2); 
keys.push_back(3); 

// usage as primitive 
// Note Container<double,double> where VALUE=double 
Container<double,Container<double,double>> c1; 
double result1 = c1.calculate(keys); 

Container<double,Container<double,Array<double>>> c2; 
Array<double> result2 = c1.calculate(keys); 

我希望能够嵌套集装箱,递归调用计算,当值不再集装箱停止。

编辑:添加代码

template<typename KEY, typename VALUE> 
class Container { 
public: 
Container(vector<KEY> x, vector<VALUE> y) 
    :_x(x), 
    _y(y) {} 

    VALUE calculate(vector<KEY> searchFors) 
{ 
    if(searchFors.size() == 0) 
    { 
     throw exception("no search keys"); 
    } 
    KEY key = searchFors[0]; 

    if(key >= *(_x.end()-1)) 
    { 
     return *(_y.end()-1); 
    } 
    if(key <= *(_x.begin())) 
    { 
     return *(_y.begin()); 
    } 
    vector<KEY>::const_iterator iSearchKey; 
    iSearchKey = upper_bound(_x.begin(), _x.end(), key); 
    size_t pos = iSearchKey - _x.begin(); 
    return (_y[pos]-_y[pos-1])/(_x[pos]-_x[pos-1]) * (key-_x[pos-1]) + _y[pos-1]; 
} 
private: 
vector<KEY> _x; 
vector<VALUE> _y; 
}; 


template<typename KEY, typename VALUE> 
class Container<KEY, Container<KEY, VALUE> > { 
public: 
Container(vector<KEY> x, vector<Container<KEY, VALUE> > y) 
    :_x(x), 
    _y(y) {} 

VALUE calculate(vector<KEY> searchFors) 
{ 
    if(searchFors.size() == 0) 
    { 
     throw exception("no search keys"); 
    } 
    KEY key = searchFors[0]; 
    vector<KEY> remainingKeys(searchFors.begin()+1, searchFors.end()); 

    if(key >= *(_x.end()-1)) 
    { 
     return (_y.end()-1)->calculate(remainingKeys); 
    } 
    if(key <= *(_x.begin())) 
    { 
     return _y.begin()->calculate(remainingKeys); 
    } 

    vector<KEY>::const_iterator iSearchKey; 
    iSearchKey = upper_bound(_x.begin(), _x.end(), key); 
    size_t pos = iSearchKey - _x.begin(); 

    VALUE upperY = _y[pos].calculate(remainingKeys); 
    VALUE lowerY = _y[pos-1].calculate(remainingKeys); 

    return (upperY-lowerY)/(_x[pos]-_x[pos-1]) * (key-_x[pos-1]) + lowerY; 
} 
private: 
vector<KEY> _x; 
vector<Container<KEY, VALUE> > _y; 
}; 

void main() 
{ 
using namespace boost::assign; 

vector<double> y; 
vector<double> z; 

y += 1,2,3,4; 
z += 1,4,9,16; 
Container<double,double> yz1(y,z); 

z.clear(); 
z += 1,8,27,64; 
Container<double,double> yz2(y,z); 

vector<double> x; 
x += 1,4; 
vector<Container<double,double> > ys; 
ys += yz1,yz2; 

Container<double,Container<double,double> > xy(x,ys); 

    vector<double> keys; 
keys += 2.5,3.5; 
double value = xy.calculate(keys); 

    // prints 29 
cout << value << endl; 

} 

编辑:一个更有效的版本,通过存储迭代器,而不是数据

template<typename KEY, typename VALUE> 
class Container; 

template<typename KEY, typename VALUE> 
class Container_helper{ 
public: 
typedef typename std::vector<KEY>::const_iterator key_iterator_type; 
typedef VALUE value_type; 
typedef typename vector<VALUE>::const_iterator value_iterator_type; 

static value_type getValue(const value_iterator_type& iValue, 
    const key_iterator_type&, const key_iterator_type&){ 
      return *iValue; 
    } 
}; 

template<typename KEY, typename VALUE> 
class Container_helper<KEY, Container<KEY, VALUE> >{ 
public: 
typedef typename std::vector<KEY>::const_iterator key_iterator_type; 
    typedef typename Container_helper<KEY, VALUE>::value_type value_type; 
typedef typename std::vector<Container<KEY, VALUE> >::const_iterator value_iterator_type; 

static value_type getValue(const value_iterator_type& iValue, 
    const key_iterator_type& xBegin, const key_iterator_type& xEnd) 
{ 
      return (*iValue)(xBegin,xEnd); 
    } 
}; 

template<typename KEY, typename VALUE> 
class Container { 

typedef typename std::vector<KEY>::const_iterator key_iterator_type; 
typedef typename std::vector<VALUE>::const_iterator value_iterator_type; 
typedef typename Container_helper<KEY, VALUE>::value_type value_type; 

public: 
Container(const key_iterator_type& xBegin, 
      const key_iterator_type& xEnd,   
      const value_iterator_type& yBegin, 
      const value_iterator_type& yEnd) 
    :_xBegin(xBegin),_xEnd(xEnd),_yBegin(yBegin),_yEnd(yEnd) {} 
Container(const Container& source) 
    :_xBegin(source._xBegin),_xEnd(source._xEnd), 
    _yBegin(source._yBegin),_yEnd(source._yEnd) {} 
    Container& operator=(const Container& source) 
{ 
    _xBegin = source._xBegin; 
    _xEnd = source._xEnd; 
    _yBegin = source._yBegin; 
    _yEnd = source._yEnd; 
    return *this; 
} 


public: 
    value_type 
operator()(const key_iterator_type& searchBegin, const key_iterator_type& searchEnd) const 
{ 
    if(searchBegin == searchEnd) 
    { 
     throw exception("no search keys"); 
    } 
    KEY key = *searchBegin; 
    key_iterator_type searchNext = searchBegin + 1; 

       if(key >= *(_xEnd-1)) 
       { 
        return Container_helper<KEY,VALUE>::getValue(_yEnd-1, searchNext, searchEnd); 
       } 
       if(key <= *_xBegin) 
       { 
        return Container_helper<KEY,VALUE>::getValue(_yBegin, searchNext, searchEnd); 
       } 

       key_iterator_type iSearchKey = upper_bound(_xBegin, _xEnd, key); 
       size_t pos = iSearchKey - _xBegin; 

    KEY lowerX = *(_xBegin+pos-1); 
    KEY upperX = *(_xBegin+pos); 

       value_type upperY = Container_helper<KEY,VALUE>:: 
     getValue(_yBegin+pos, searchNext, searchEnd); 
       value_type lowerY = Container_helper<KEY,VALUE>:: 
     getValue(_yBegin+pos-1, searchNext, searchEnd); 

       return (upperY-lowerY)/(upperX-lowerX) * (key-lowerX) + lowerY; 
     } 

    private: 
    key_iterator_type _xBegin; 
    key_iterator_type _xEnd;  
    value_iterator_type _yBegin; 
    value_iterator_type _yEnd; 
    }; 
+1

“as primitives”的用法是什么样子? –

+1

什么是getLower和getUpper? 'calculate'的第二个重载是什么? 'calculate'中的'return'在哪里?在这里很难看到你想要的东西。 – pmr

+0

编辑的问题。感谢您的反馈意见。 –

回答

0

如果我理解你的权利,我认为这可能是对你有用

template<typename KEY, typename VALUE> 
class Container { 
public: 
    VALUE calculate(vector<KEY> searchFors); 
    . 
    . 
    . 
private: 
    vector<pair<KEY,VALUE> > _data; 

}; 

template<typename KEY, typename VALUE> 
VALUE Container<KEY, VALUE>::calculate(vector<KEY> searchFors) 
{ 
    // operate on non-container (simple) values. 
} 

template<typename KEY, typename VALUE> 
class Container<KEY, Container<KEY, VALUE> > { 
public: 
    VALUE calculate(vector<KEY> searchFors); 
    . 
    . 
    . 
private: 
    vector<pair<KEY, Container<KEY, VALUE> > > _data; 
}; 

template<typename KEY, typename VALUE> 
VALUE Container<KEY, Container<KEY, VALUE> >::calculate(vector<KEY> searchFors) 
{ 
    // operate on container values 
} 

这些功能应该很好的封装是什么基地类型和容器是什么。唯一的问题是它只适用于一个容器类 - 如果你有多种类型的容器,你可能会使用某种类型的特性。

编辑:

看到你确切的例子后,我看到这是可能与分离功能为辅助类,但它象垃圾一样清除命名空间的额外类。如果你不介意,那么代码在这里:

#include <iostream> 
#include <vector> 

#include <boost/assign.hpp> 

using namespace std; 

template<typename KEY, typename VALUE> 
class Container; 

template<typename KEY, typename VALUE> 
class Container_helper{ 
public: 
    typedef VALUE value_type; 

    static value_type calculate(VALUE& val, vector<KEY> /*remainingKeys*/){ 
     return val; 
    } 
}; 

template<typename KEY, typename VALUE> 
class Container_helper<KEY, Container<KEY, VALUE> >{ 
public: 
    typedef typename Container_helper<KEY, VALUE>::value_type value_type; 

    static value_type calculate(Container<KEY, VALUE>& val, vector<KEY> remainingKeys){ 
     return val.calculate(remainingKeys); 
    } 
}; 

template<typename KEY, typename VALUE> 
class Container { 

public: 

Container(vector<KEY> x, vector<VALUE> y) 
    :_x(x), 
    _y(y) {} 

public: 

    typename Container_helper<KEY, VALUE>::value_type calculate(vector<KEY> searchFors){ 
      if(searchFors.size() == 0) 
     { 
      throw exception(/*"no search keys"*/); 
     } 
     KEY key = searchFors[0]; 
     vector<KEY> remainingKeys(searchFors.begin()+1, searchFors.end()); 

     if(key >= *(_x.end()-1)) 
     { 
      return Container_helper<KEY, VALUE>::calculate(*(_y.end()-1), remainingKeys); 
     } 
     if(key <= *(_x.begin())) 
     { 
      return Container_helper<KEY, VALUE>::calculate((*_y.begin()), remainingKeys); 
     } 

     typename vector<KEY>::const_iterator iSearchKey; 
     iSearchKey = upper_bound(_x.begin(), _x.end(), key); 
     size_t pos = iSearchKey - _x.begin(); 

     typename Container_helper<KEY, VALUE>::value_type upperY = Container_helper<KEY, VALUE>::calculate(_y[pos], remainingKeys); 
     typename Container_helper<KEY, VALUE>::value_type lowerY = Container_helper<KEY, VALUE>::calculate(_y[pos-1], remainingKeys); 

     return (upperY-lowerY)/(_x[pos]-_x[pos-1]) * (key-_x[pos-1]) + lowerY; 
    } 

private: 
vector<KEY> _x; 
vector<VALUE> _y; 
}; 


int main(int argc, char* argv[]) 
{ 
using namespace boost::assign; 

vector<double> y; 
vector<double> z; 

y += 1,2,3,4; 
z += 1,4,9,16; 
Container<double,double> yz1(y,z); 

z.clear(); 
z += 1,8,27,64; 
Container<double,double> yz2(y,z); 

vector<double> x; 
x += 1,4; 
vector<Container<double,double> > ys; 
ys += yz1,yz2; 

Container<double,Container<double,double> > xy(x,ys); 

    vector<double> keys; 
keys += 2.5,3.5; 
double value = xy.calculate(keys); 

    // prints 29 
cout << value << endl; 

} 
+0

我需要针对每种VALUE类型进行专业化吗? VALUE也可以是支持+, - ,*,/的数组。 –

+0

不,你不知道。你只需要记住,如果可能的话,你应该递归地编写计算(和其他方法)方法 - 每个计算方法只应该在顶层列表上工作 - 以及是否需要调用子列表迭代方法。这样你的Container类可以嵌套到任意级别。 –

+0

有没有一种方法可以将计算中的通用代码块分解出来? –

0

我想在你的容器类,它让你可以,定义一个方法VALUE和KEY并返回VALUE。然后你可以指定这个函数来返回一个值或者调用函子。或者(我可能会这样做)是编写一个Wrapper类,它将一个Primitive包装到一个Functor中,所以当你需要一个基元时,只需使用Wrapper创建一个Container。 这应该是这样的(这可能不编译)

template<typename KEY, typename VALUE> 
class PrimitiveToFunctor { 
    public: 
    PrimitiveToFunctor(VALUE v) { 
     value = v; 
    } 
    VALUE function_to_wrap(KEY key) { 
     return value; 
    } 
    private: 
    VALUE value; 
} 

Container<double, Container<double, PrimitiveToFunction<double>>> c1; 
+0

谢谢,我正在思考。 –