[英]c++ template: How to dynamically choose between classes and primitive types
是否可以使用模板來實現以下所示的思想:
// 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;
};
請注意,VALUE需要實現operator()。 如何使它可以在基元或函子之間進行選擇? 例如,如果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);
我希望能夠嵌套容器,以遞歸方式調用計算,當VALUE不再是容器時停止。
編輯:添加代碼
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;
};
我認為您可以在Container類中定義一個獲得VALUE和KEY並返回VALUE的方法。 然后,您可以指定此函數為返回值或調用函子。 或者(我可能會做的)是編寫一個包裝器類,該包裝器將基元包裝到函子,以便當您需要基元時,只需使用包裝器創建一個容器即可。 看起來像這樣(可能無法編譯)
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;
如果我沒看錯,我認為這可能對您有用
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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.