Appending values to a variant of containers - c++

I have a container variant as follows:
typedef boost::variant<std::vector<int>, std::vector<std::string> > Container;
And I populate a Container object from a ValueContainer object (a C struct) as follows:
class ContainerAppender: public boost::static_visitor<>
{
public:
void setValueToAppend(const Value* value){
_value = value;
}
void operator()(std::vector<int>& container) const {
container.push_back(_value->value.i);
}
void operator()(std::vector<std::string>& container) const {
container.push_back(_value->value.s);
}
...
private:
const Value* _value;
};
void fillContainer(Container& container, ValueContainer* cContainer) {
if(cContainer) {
ContainerAppender append;
for(int i = 0; i < cContainer->nunberOfValues; i++) {
append.setValueToAppend(&cContainer->values[i]);
boost::apply_visitor(append, container);
}
}
}
I am not free to change the C structures.
I don't like my solution for populating the container as I am visiting for every loop despite the fact that the container type never changes. It feels that there is a better way of doing. Can you help?
here's the C union:
typedef struct Value {
union {
int i;
const char* s;
} value;
} Value_T;
typedef struct ValueContainer {
Type type;
unsigned int numberOfValues;
Value *values;
} ValueContainer_T;

Is the visitor really necessary? Consider this:
template<typename T>
T value_get(Value_T const &c_variant) {
return T();
}
template<>
int value_get<int>(Value_T const &c_variant) {
return c_variant.i;
}
template<>
const char* value_get<const char*>(Value_T const &c_variant) {
return c_variant.s;
}
template<typename T>
std::vector<T> fill_vector(ValueContainer_T const& c_container) {
std::vector<T> cpp_container(c_container.numberOfValues);
for(size_t i = 0; i < c_container.numberOfValues; ++i)
cpp_container[i] = value_get<T>(c_container.values[i]);
return cpp_container;
}
Looks simpler to me.

Related

c++: Can I overload operator[][]? [duplicate]

Is it possible to overload [] operator twice? To allow, something like this: function[3][3](like in a two dimensional array).
If it is possible, I would like to see some example code.
You can overload operator[] to return an object on which you can use operator[] again to get a result.
class ArrayOfArrays {
public:
ArrayOfArrays() {
_arrayofarrays = new int*[10];
for(int i = 0; i < 10; ++i)
_arrayofarrays[i] = new int[10];
}
class Proxy {
public:
Proxy(int* _array) : _array(_array) { }
int operator[](int index) {
return _array[index];
}
private:
int* _array;
};
Proxy operator[](int index) {
return Proxy(_arrayofarrays[index]);
}
private:
int** _arrayofarrays;
};
Then you can use it like:
ArrayOfArrays aoa;
aoa[3][5];
This is just a simple example, you'd want to add a bunch of bounds checking and stuff, but you get the idea.
For a two dimensional array, specifically, you might get away with a single operator[] overload that returns a pointer to the first element of each row.
Then you can use the built-in indexing operator to access each element within the row.
An expression x[y][z] requires that x[y] evaluates to an object d that supports d[z].
This means that x[y] should be an object with an operator[] that evaluates to a "proxy object" that also supports an operator[].
This is the only way to chain them.
Alternatively, overload operator() to take multiple arguments, such that you might invoke myObject(x,y).
It is possible if you return some kind of proxy class in first [] call. However, there is other option: you can overload operator() that can accept any number of arguments (function(3,3)).
One approach is using std::pair<int,int>:
class Array2D
{
int** m_p2dArray;
public:
int operator[](const std::pair<int,int>& Index)
{
return m_p2dArray[Index.first][Index.second];
}
};
int main()
{
Array2D theArray;
pair<int, int> theIndex(2,3);
int nValue;
nValue = theArray[theIndex];
}
Of course, you may typedef the pair<int,int>
You can use a proxy object, something like this:
#include <iostream>
struct Object
{
struct Proxy
{
Object *mObj;
int mI;
Proxy(Object *obj, int i)
: mObj(obj), mI(i)
{
}
int operator[](int j)
{
return mI * j;
}
};
Proxy operator[](int i)
{
return Proxy(this, i);
}
};
int main()
{
Object o;
std::cout << o[2][3] << std::endl;
}
If, instead of saying a[x][y], you would like to say a[{x,y}], you can do like this:
struct Coordinate { int x, y; }
class Matrix {
int** data;
operator[](Coordinate c) {
return data[c.y][c.x];
}
}
It 'll be great if you can let me know what function, function[x] and function[x][y] are. But anyway let me consider it as an object declared somewhere like
SomeClass function;
(Because you said that it's operator overload, I think you won't be interested at array like SomeClass function[16][32];)
So function is an instance of type SomeClass. Then look up declaration of SomeClass for the return type of operator[] overload, just like
ReturnType operator[](ParamType);
Then function[x] will have the type ReturnType. Again look up ReturnType for the operator[] overload. If there is such a method, you could then use the expression function[x][y].
Note, unlike function(x, y), function[x][y] are 2 separate calls. So it's hard for compiler or runtime garantees the atomicity unless you use a lock in the context. A similar example is, libc says printf is atomic while successively calls to the overloaded operator<< in output stream are not. A statement like
std::cout << "hello" << std::endl;
might have problem in multi-thread application, but something like
printf("%s%s", "hello", "\n");
is fine.
template<class F>
struct indexer_t{
F f;
template<class I>
std::result_of_t<F const&(I)> operator[](I&&i)const{
return f(std::forward<I>(i))1;
}
};
template<class F>
indexer_t<std::decay_t<F>> as_indexer(F&& f){return {std::forward<F>(f)};}
This lets you take a lambda, and produce an indexer (with [] support).
Suppose you have an operator() that supports passing both coordinates at onxe as two arguments. Now writing [][] support is just:
auto operator[](size_t i){
return as_indexer(
[i,this](size_t j)->decltype(auto)
{return (*this)(i,j);}
);
}
auto operator[](size_t i)const{
return as_indexer(
[i,this](size_t j)->decltype(auto)
{return (*this)(i,j);}
);
}
And done. No custom class required.
#include<iostream>
using namespace std;
class Array
{
private: int *p;
public:
int length;
Array(int size = 0): length(size)
{
p=new int(length);
}
int& operator [](const int k)
{
return p[k];
}
};
class Matrix
{
private: Array *p;
public:
int r,c;
Matrix(int i=0, int j=0):r(i), c(j)
{
p= new Array[r];
}
Array& operator [](const int& i)
{
return p[i];
}
};
/*Driver program*/
int main()
{
Matrix M1(3,3); /*for checking purpose*/
M1[2][2]=5;
}
struct test
{
using array_reference = int(&)[32][32];
array_reference operator [] (std::size_t index)
{
return m_data[index];
}
private:
int m_data[32][32][32];
};
Found my own simple solution to this.
vector< vector< T > > or T** is required only when you have rows of variable length
and way too inefficient in terms of memory usage/allocations
if you require rectangular array consider doing some math instead!
see at() method:
template<typename T > class array2d {
protected:
std::vector< T > _dataStore;
size_t _sx;
public:
array2d(size_t sx, size_t sy = 1): _sx(sx), _dataStore(sx*sy) {}
T& at( size_t x, size_t y ) { return _dataStore[ x+y*sx]; }
const T& at( size_t x, size_t y ) const { return _dataStore[ x+y*sx]; }
const T& get( size_t x, size_t y ) const { return at(x,y); }
void set( size_t x, size_t y, const T& newValue ) { at(x,y) = newValue; }
};
The shortest and easiest solution:
class Matrix
{
public:
float m_matrix[4][4];
// for statements like matrix[0][0] = 1;
float* operator [] (int index)
{
return m_matrix[index];
}
// for statements like matrix[0][0] = otherMatrix[0][0];
const float* operator [] (int index) const
{
return m_matrix[index];
}
};
It is possible to overload multiple [] using a specialized template handler. Just to show how it works :
#include <iostream>
#include <algorithm>
#include <numeric>
#include <tuple>
#include <array>
using namespace std;
// the number '3' is the number of [] to overload (fixed at compile time)
struct TestClass : public SubscriptHandler<TestClass,int,int,3> {
// the arguments will be packed in reverse order into a std::array of size 3
// and the last [] will forward them to callSubscript()
int callSubscript(array<int,3>& v) {
return accumulate(v.begin(),v.end(),0);
}
};
int main() {
TestClass a;
cout<<a[3][2][9]; // prints 14 (3+2+9)
return 0;
}
And now the definition of SubscriptHandler<ClassType,ArgType,RetType,N> to make the previous code work. It only shows how it can be done. This solution is optimal nor bug-free (not threadsafe for instance).
#include <iostream>
#include <algorithm>
#include <numeric>
#include <tuple>
#include <array>
using namespace std;
template <typename ClassType,typename ArgType,typename RetType, int N> class SubscriptHandler;
template<typename ClassType,typename ArgType,typename RetType, int N,int Recursion> class SubscriptHandler_ {
ClassType*obj;
array<ArgType,N+1> *arr;
typedef SubscriptHandler_<ClassType,ArgType,RetType,N,Recursion-1> Subtype;
friend class SubscriptHandler_<ClassType,ArgType,RetType,N,Recursion+1>;
friend class SubscriptHandler<ClassType,ArgType,RetType,N+1>;
public:
Subtype operator[](const ArgType& arg){
Subtype s;
s.obj = obj;
s.arr = arr;
arr->at(Recursion)=arg;
return s;
}
};
template<typename ClassType,typename ArgType,typename RetType,int N> class SubscriptHandler_<ClassType,ArgType,RetType,N,0> {
ClassType*obj;
array<ArgType,N+1> *arr;
friend class SubscriptHandler_<ClassType,ArgType,RetType,N,1>;
friend class SubscriptHandler<ClassType,ArgType,RetType,N+1>;
public:
RetType operator[](const ArgType& arg){
arr->at(0) = arg;
return obj->callSubscript(*arr);
}
};
template<typename ClassType,typename ArgType,typename RetType, int N> class SubscriptHandler{
array<ArgType,N> arr;
ClassType*ptr;
typedef SubscriptHandler_<ClassType,ArgType,RetType,N-1,N-2> Subtype;
protected:
SubscriptHandler() {
ptr=(ClassType*)this;
}
public:
Subtype operator[](const ArgType& arg){
Subtype s;
s.arr=&arr;
s.obj=ptr;
s.arr->at(N-1)=arg;
return s;
}
};
template<typename ClassType,typename ArgType,typename RetType> struct SubscriptHandler<ClassType,ArgType,RetType,1>{
RetType operator[](const ArgType&arg) {
array<ArgType,1> arr;
arr.at(0)=arg;
return ((ClassType*)this)->callSubscript(arr);
}
};
With a std::vector<std::vector<type*>>, you can build the inside vector using custom input operator that iterate over your data and return a pointer to each data.
For example:
size_t w, h;
int* myData = retrieveData(&w, &h);
std::vector<std::vector<int*> > data;
data.reserve(w);
template<typename T>
struct myIterator : public std::iterator<std::input_iterator_tag, T*>
{
myIterator(T* data) :
_data(data)
{}
T* _data;
bool operator==(const myIterator& rhs){return rhs.data == data;}
bool operator!=(const myIterator& rhs){return rhs.data != data;}
T* operator*(){return data;}
T* operator->(){return data;}
myIterator& operator++(){data = &data[1]; return *this; }
};
for (size_t i = 0; i < w; ++i)
{
data.push_back(std::vector<int*>(myIterator<int>(&myData[i * h]),
myIterator<int>(&myData[(i + 1) * h])));
}
Live example
This solution has the advantage of providing you with a real STL container, so you can use special for loops, STL algorithms, and so on.
for (size_t i = 0; i < w; ++i)
for (size_t j = 0; j < h; ++j)
std::cout << *data[i][j] << std::endl;
However, it does create vectors of pointers, so if you're using small datastructures such as this one you can directly copy the content inside the array.
Sample code:
template<class T>
class Array2D
{
public:
Array2D(int a, int b)
{
num1 = (T**)new int [a*sizeof(int*)];
for(int i = 0; i < a; i++)
num1[i] = new int [b*sizeof(int)];
for (int i = 0; i < a; i++) {
for (int j = 0; j < b; j++) {
num1[i][j] = i*j;
}
}
}
class Array1D
{
public:
Array1D(int* a):temp(a) {}
T& operator[](int a)
{
return temp[a];
}
T* temp;
};
T** num1;
Array1D operator[] (int a)
{
return Array1D(num1[a]);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Array2D<int> arr(20, 30);
std::cout << arr[2][3];
getchar();
return 0;
}
Using C++11 and the Standard Library you can make a very nice two-dimensional array in a single line of code:
std::array<std::array<int, columnCount>, rowCount> myMatrix {0};
std::array<std::array<std::string, columnCount>, rowCount> myStringMatrix;
std::array<std::array<Widget, columnCount>, rowCount> myWidgetMatrix;
By deciding the inner matrix represents rows, you access the matrix with an myMatrix[y][x] syntax:
myMatrix[0][0] = 1;
myMatrix[0][3] = 2;
myMatrix[3][4] = 3;
std::cout << myMatrix[3][4]; // outputs 3
myStringMatrix[2][4] = "foo";
myWidgetMatrix[1][5].doTheStuff();
And you can use ranged-for for output:
for (const auto &row : myMatrix) {
for (const auto &elem : row) {
std::cout << elem << " ";
}
std::cout << std::endl;
}
(Deciding the inner array represents columns would allow for an foo[x][y] syntax but you'd need to use clumsier for(;;) loops to display output.)

dynamically call same named function with different return type

I have a situation here...
I want to design a Factory where I can call a function with same name and no parameters but return different data Types. Based on the SubClassName I need to instantiate the Object.
Need help or lead on any design pattern to follow?
EDIT:
An abstract pseudo code...
class parent{
public:
virtual string getName() = 0;
//some virtual function.. not sure how to design. As the return type is dynamic.
*** getValue(){}
};
class A : public parent{
int x;
public:
virtual string getName(){ return "A";}
virtual int getValue(){retun x;}
};
class B : public parent{
string s;
public:
virtual string getName(){ return "B";}
virtual string getValue(){ return s;}
};
void main(){
string callingClass = "B";
parent * arrayPtrs[2];
arrayPtrs[0] = new A;
arrayPtrs[1] = new B;
for (loop through array, through iterator i){
if(arrayPtrs[i]->getName == callingClass ){
cout<<arrayPtrs[i]->getValue;
}
}
}
In C++ a function can only have one return type at a time, and you cannot change that dynamically.
However - as suggested by #mch - you can use template specializations. Keep in mind though, that this method is not dynamic. Your functions will be generated at compile time.
If I understood your question correctly, maybe this can be of help.
class MyObject1
{
//...
};
class MyObject2
{
//...
};
template<typename T>
struct Factory
{
constexpr static T gen();
};
template<>
struct Factory<MyObject1>
{
constexpr static MyObject1 gen()
{
return MyObject1(/*... whatever parameters you see fit ...*/);
}
};
template<>
struct Factory<MyObject2>
{
constexpr static MyObject2 gen()
{
return MyObject2(/*... whatever parameters you see fit ...*/);
}
};
int main()
{
auto myObj = Factory<MyObject1>::gen();
return 0;
}
Although this method seems fairly useless to me. You could simply call the desired constructor instead of this.
But then again, I'm not sure if this is what you thought of. If I made any mistakes please feel free, to correct me. I'll try to edit my answer best as I can.
EDIT:
To keep the virtual functionality too, the only way I can think of is type erasure: see https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Type_Erasure
The closest I could get to what you've asked for is this:
#include <iostream>
#include <string>
#include <any>
class parent {
public:
// you can use this too but I think type checking is more handy
// see in main function
/* virtual std::string getName() const = 0; */
virtual std::any getValue() const = 0;
};
class A : public parent {
public:
typedef int value_type;
private:
value_type x;
public:
A(value_type x) :
x(x)
{}
/* virtual std::string getName() const override { return "A"; } */
virtual std::any getValue() const override
{ return this->x; }
};
class B : public parent {
public:
typedef std::string value_type;
private:
value_type s;
public:
B(const value_type& s) :
s(s)
{}
/* virtual std::string getName() const override { return "B"; } */
virtual std::any getValue() const override
{ return this->s; }
};
int main(){
using callingClass = A;
parent* arrayPtrs[2];
arrayPtrs[0] = new A(42);
arrayPtrs[1] = new B("my string");
for (unsigned i = 0; i < sizeof(arrayPtrs) / sizeof(parent*); ++i)
{
// Note:
// dynamic cast will return nullptr if $callingClass
// is not a derived class
if (dynamic_cast<callingClass*>(arrayPtrs[i]))
std::cout << std::any_cast<callingClass::value_type>(arrayPtrs[i]->getValue()) << std::endl;
}
return 0;
}
I hope this one helps.
Note, that I used dynamic_cast to check the correct type. If you know a better solution, you can use that, too. But under these circumstances I couldn't think of any better.
EDIT2:
#include <iostream>
#include <string>
#include <tuple>
class some
{
using id = size_t;
template<typename T>
struct type { static void id() { } };
template<typename T>
static id type_id() { return reinterpret_cast<id>(&type<T>::id); }
template<typename T>
using decay = typename std::decay<T>::type;
template<typename T>
using none = typename std::enable_if<!std::is_same<some, T>::value>::type;
struct base
{
virtual ~base() { }
virtual bool is(id) const = 0;
virtual base *copy() const = 0;
} *p = nullptr;
template<typename T>
struct data : base, std::tuple<T>
{
using std::tuple<T>::tuple;
T &get() & { return std::get<0>(*this); }
T const &get() const& { return std::get<0>(*this); }
bool is(id i) const override { return i == type_id<T>(); }
base *copy() const override { return new data{get()}; }
};
template<typename T>
T &stat() { return static_cast<data<T>&>(*p).get(); }
template<typename T>
T const &stat() const { return static_cast<data<T> const&>(*p).get(); }
template<typename T>
T &dyn() { return dynamic_cast<data<T>&>(*p).get(); }
template<typename T>
T const &dyn() const { return dynamic_cast<data<T> const&>(*p).get(); }
public:
some() { }
~some() { delete p; }
some(some &&s) : p{s.p} { s.p = nullptr; }
some(some const &s) : p{s.p->copy()} { }
template<typename T, typename U = decay<T>, typename = none<U>>
some(T &&x) : p{new data<U>{std::forward<T>(x)}} { }
some &operator=(some s) { swap(*this, s); return *this; }
friend void swap(some &s, some &r) { std::swap(s.p, r.p); }
void clear() { delete p; p = nullptr; }
bool empty() const { return p; }
template<typename T>
bool is() const { return p ? p->is(type_id<T>()) : false; }
template<typename T> T &&_() && { return std::move(stat<T>()); }
template<typename T> T &_() & { return stat<T>(); }
template<typename T> T const &_() const& { return stat<T>(); }
template<typename T> T &&cast() && { return std::move(dyn<T>()); }
template<typename T> T &cast() & { return dyn<T>(); }
template<typename T> T const &cast() const& { return dyn<T>(); }
template<typename T> operator T &&() && { return std::move(_<T>()); }
template<typename T> operator T &() & { return _<T>(); }
template<typename T> operator T const&() const& { return _<T>(); }
};
using any = some;
class parent {
public:
// you can use this too but I think type checking is more handy
/* virtual std::string getName() const = 0; */
virtual any getValue() const = 0;
};
class A : public parent {
public:
typedef int value_type;
private:
value_type x;
public:
A(value_type x) :
x(x)
{}
/* virtual std::string getName() const override { return "A"; } */
virtual any getValue() const override
{ return this->x; }
};
class B : public parent {
public:
typedef std::string value_type;
private:
value_type s;
public:
B(const value_type& s) :
s(s)
{}
/* virtual std::string getName() const override { return "B"; } */
virtual any getValue() const override
{ return this->s; }
};
int main(){
using callingClass = A;
parent* arrayPtrs[2];
arrayPtrs[0] = new A(42);
arrayPtrs[1] = new B("my string");
for (unsigned i = 0; i < sizeof(arrayPtrs) / sizeof(parent*); ++i)
{
// Note:
// dynamic cast will return nullptr if $callingClass
// is not a derived class
if (dynamic_cast<callingClass*>(arrayPtrs[i]))
std::cout << arrayPtrs[i]->getValue()._<callingClass::value_type>() << std::endl;
}
return 0;
}
This snipped is in case you cannot use C++17 features, and is based on:
any class

C++ Similar functions using different data types

I have two functions which are exactly the same, except that one of them uses a stack for its operations and the other one uses a queue:
void doQueue()
{
std::queue<int> q;
...
...
q.push(someValue);
...
...
int tmp = q.front();
q.pop()
}
void doStack()
{
std::stack<int> s;
...
...
s.push(someValue);
...
...
int tmp = s.top();
s.pop()
}
I want to eliminate duplicate code. As queue uses the front function to retrieve the first value and stack uses the top function, I thought that templates may not work since functions with different names have to be called.
My other idea was to create an interface which will be as a wrapper to both data structures and I can pass around the one that I need.:
class Data
{
public:
virtual void push(const int v) = 0;
virtual int pop() = 0;
};
class StackData : public Data
{
private:
std::stack<int> _stack;
public:
virtual void push(const int v) {_stack.push(v);}
virtual int pop()
{
int ret = _stack.top();
_stack.pop();
return ret;
}
};
class QueueData : public Data
{
private:
std::queue<int> _queue;
public:
virtual void push(const int v) {_queue.push(v);}
virtual int pop()
{
int ret = _queue.front();
_queue.pop();
return ret;
}
};
void doData(Data& dataType)
{
...
dataType.push(someValue);
...
int tmp = dataType.pop();
}
void doQueue()
{
QueueData queueData;
doData(queueData);
}
void doStack()
{
StackData stackData;
doData(stackData);
}
But I think there should be an easier and better way to perform this operation.
Here's one way - a wrapper template with partial specialisation on underlying container type:
#include <stack>
#include <queue>
template<class Container>
struct generic_sequence_ops;
template<class T, class UnderlyingContainer>
struct generic_sequence_ops<std::stack<T, UnderlyingContainer>>
{
using container_type = std::stack<T, UnderlyingContainer>;
using value_type = typename container_type::value_type;
generic_sequence_ops(container_type& c) : c(c) {}
void add_one(value_type v)
{
c.push(std::move(v));
}
void remove_one()
{
c.pop();
}
value_type& current()
{
return c.top();
}
container_type& c;
};
template<class T, class UnderlyingContainer>
struct generic_sequence_ops<std::queue<T, UnderlyingContainer>>
{
using container_type = std::queue<T, UnderlyingContainer>;
using value_type = typename container_type::value_type;
generic_sequence_ops(container_type& c) : c(c) {}
void add_one(value_type v)
{
c.push(std::move(v));
}
void remove_one()
{
c.pop();
}
value_type& current()
{
return c.back();
}
container_type& c;
};
template<class Container>
auto make_generic_sequence_ops(Container& cont)
{
return generic_sequence_ops<std::decay_t<Container>>(cont);
}
template<class Container>
int doContainer(Container& cont)
{
auto s = make_generic_sequence_ops(cont);
s.add_one(6);
int val = s.current();
s.remove_one();
return val;
}
int main()
{
std::queue<int> q;
std::stack<int> s;
doContainer(q);
doContainer(s);
}

Inheritance vs class template specialization. Design dude

I have an implementation design trouble. I hope you can help me. Suppose I have the following class
class A
{
public:
vector<int> v() const { return m_v; }
bool isValid() const { return m_v.size() > m_components; }
int operator [] (const int index) const { return m_v[index]; }
...
private:
vector<int> m_v;
int m_components;
}
Now I want the m_v vector can be of different types, so I can template the class:
template<typename T>
class A
{
public:
vector<T> v() const { return m_v; }
T operator [] (const int index) const { return m_v[index]; }
...
private:
vector<T> m_v;
int m_components;
}
However, I realized that when the type T is for example double I need to extend class A and add more attributes, for example another vector<bool> m_foo; and change several methods that should use these new attributes.
Here is where I have the doubt. I think I have several options:
Option 1: I can make a non-templated base class A with the implementation of all the common methods, and derive several classes each one for each different type (with its own specific class attributes and method implementations), i.e.: Aint, Adouble, Afloat. This option requires that the vector<...> m_v; is stored at each derived class, and hence I have to replicate several times all the same code to access the m_v; attribute in each derived class. In the example, such methods are only v(), operator [] and isValid(), however in the real problem there are much more.
Option 2: Template specialization. I can specialize the class template for each type and hence provide only the implementation of the specific methods that change depending on the T type. However, this enforces to store a lot of stuff in the template class that is only used if T is of a specific type, i.e. the m_foo vector that is only used when T type is double (in the proposed example). Therefore, I am wasting memory. Moreover, it seems not very elegant or even coherent to implement a template class and provide template class specialization for almost most of the template types and store specific attributes that are only used for specific types.
I don't know if I managed to explain my problem well. Hope so.
Thank you in advance.
Javier.
This kind of depends.
General rule of thumb is asking yourself if "ADouble is-a A". When those have a is-a relationship you should use inheritance.
But you also have type dependency which is not really a "is-a" relationship.
You can also use both options: Having a base class with the common functionality which takes a template argument and having child classes with the additions they need. So you don't need to reimplement all the type dependend functions
So:
template<typename T>
class A
{
public:
vector<T> v() const { return m_v; }
T operator [] (const int index) const { return m_v[index]; }
...
private:
vector<T> m_v;
...
};
class ADouble : public A<double>
{
...
};
Btw: why do you think templates take more memory?
Partially specialise specific operations in your class (without specialising the whole class) with sub-operations.
#include <vector>
namespace detail
{
// general concept of indexing into something
template<class T> struct index_operation;
// indexing into most vectors
template <class T> struct index_operation<std::vector<T>>
{
T& operator()(std::vector<T>& v, std::size_t i) const
{
return v[i];
}
T const& operator()(std::vector<T> const& v, std::size_t i) const
{
return v[i];
}
};
// indexing into a vector<bool>
template <> struct index_operation<std::vector<bool>>
{
std::vector<bool>::reference operator()(std::vector<bool>& v, std::size_t i) const
{
return v[i];
}
std::vector<bool>::const_reference operator()(std::vector<bool> const& v, std::size_t i) const
{
return v[i];
}
};
}
template<typename T>
class A
{
using vector_type = std::vector<T>;
public:
std::vector<T> v() const { return m_v; }
decltype(auto) operator [] (const int index) const
{
auto op = detail::index_operation<vector_type>();
return op(m_v, index);
}
private:
std::vector<T> m_v;
};
I will try to formulate the question with an example closely to my real problem although it becomes a longer post.
Option1: Consider the following class implementation based on templates and template specialization.
template<typename T>
class A
{
public:
A() {}
vector<T> v() const { return m_v; }
bool isValid() const { return m_v.size() >= m_components; }
T operator [] (const int i) const { return m_v[i]; }
T& operator [] (const int i) { return m_v[i]; }
int components() const { return m_components; }
double value() const { return m_value; }
void method1();
private:
vector<T> m_v;
int m_components;
double m_value;
vector<bool> m_indices; // this is only used when T is int
map<int, char> m_map; // this is only used when T is double
queue<int> m_queue; // this is only used when T is bool
};
template<>
void A<int>::method1()
{
for (int i = 0; i < m_components; ++i) m_v.push_back(i);
// stuff only for int case
for (int i = 0; i < m_components; ++i) { i % 2 == 0 ? m_indices[i] = true : m_indices[i] = false; }
}
template<>
void A<double>::method1()
{
for (int i = 0; i < m_components; ++i) m_v.push_back(i);
// stuff only for double case
for (int i = 0; i < m_components; ++i) { i % 2 == 0 ? m_map[i] = 'e' : m_map[i] = 'o'; }
}
template<>
void A<bool>::method1()
{
for (int i = 0; i < m_components; ++i) m_v.push_back(i);
// stuff only for bool case
for (int i = 0; i < m_components; ++i) { i % 2 == 0 ? m_queue.push(1) : m_queue.push(0); }
}
As you can see, there are several methods that are common regardless the T type and involves the use of the m_v vector (methods: v(), isValid(), operator[]). However, there are also other methods (method1()) that have a specific implementation depending on T type, and also requires the use of specific data structures depending on this type (queues, maps, vectors). I see very very ugly the definition of queues, maps, vectors, etc in the class although if they are only used in concrete cases depending the T type.
Option 2: The other alternative:
class A
{
public:
A() {}
int components() const { return m_components; }
double value() const { return m_value; }
virtual void method1() == 0;
protected:
int m_components;
double m_value;
};
/***** Derived A for int case ****/
class Aint : public A
{
public:
Aint() {}
vector<int> v() const { return m_v; }
bool isValid() const { return m_v.size() >= m_components; }
int operator [] (const int i) const { return m_v[i]; }
int& operator [] (const int i) { return m_v[i]; }
void method1();
private:
vector<int> m_v;
vector<bool> m_indices;
};
void Aint::method1()
{
for (int i = 0; i < m_components; ++i) m_v.push_back(i);
for (int i = 0; i < m_components; ++i) { i % 2 == 0 ? m_indices[i] = true : m_indices[i] = false; }
}
/***** Derived A for double case ****/
class Adouble : public A
{
public:
Adouble() {}
vector<double> v() const { return m_v; }
bool isValid() const { return m_v.size() >= m_components; }
double operator [] (const int i) const { return m_v[i]; }
double& operator [] (const int i) { return m_v[i]; }
void method1();
private:
vector<double> m_v;
map<int, char> m_map;
};
void Adouble::method1()
{
for (int i = 0; i < m_components; ++i) m_v.push_back(i);
for (int i = 0; i < m_components; ++i) { i % 2 == 0 ? m_map[i] = 'e' : m_map[i] = 'o'; }
}
/***** Derived A for bool case ****/
class Abool : public A
{
public:
Abool() {}
vector<bool> v() const { return m_v; }
bool isValid() const { return m_v.size() >= m_components; }
bool operator [] (const int i) const { return m_v[i]; }
bool& operator [] (const int i) { return m_v[i]; }
void method1();
private:
vector<bool> m_v;
queue<int> m_map;
};
void Abool::method1()
{
for (int i = 0; i < m_components; ++i) m_v.push_back(i);
for (int i = 0; i < m_components; ++i) { i % 2 == 0 ? m_queue.push(1) : m_queue.push(0); }
}
As you can see, in this case the type specific data structures (queues, maps, etc) are only defined for their required cases (not in the general class template of the Option 1). But, now the m_v vector should be defined at each derived class due to its specific type. Hence, the stuff for accesing and manipulating the vector should be replicated always in all the derived classes although they are always the same (methods v(), isValid(), operator[], etc). It also seems non-well designed.
What is the best design for that purpose?
Thank you

How to apply Template Method Pattern for functions with different signatures?

How does one provide a unified interface to sets of functions, that are used in the same way? To illustrate, please look at the set of given library functions:
/* existing library functions */
/* the signatures are different: some return int, some float */
/* set of input related functions */
int getInputValue() { return 42; }
size_t getInputSize() { return 1; }
/* set of output related functions */
int getOutputValue() { return 21; }
size_t getOutputSize() { return 1; }
/* set of parameter related functions */
float getParameterValue() { return 3.14; }
size_t getParameterSize() { return 1; }
and assume they are used in the same way:
if (getSize() > 0) {
T value = getValue()
A) What is a good way to provide getSize() and getValue()?
I first though that Template Method Pattern is what I want, but I couldn't apply it, because in contrast to the Worker in the Template Method Pattern, my functions have different signatures.
So what I did instead:
/* I want to provide a uniform interface */
/* the specific part of inputs, outputs and parameters is in the traits */
struct input_traits {
typedef int value_type;
static int getValue() { return getInputValue(); }
static size_t getSize() { return getInputSize(); }
};
struct output_traits {
typedef int value_type;
static int getValue() { return getOutputValue(); }
static size_t getSize() { return getOutputSize(); }
};
struct parameter_traits {
typedef float value_type;
static float getValue() { return getParameterValue(); }
static size_t getSize() { return getParameterSize(); }
};
/* the common part (they are used in the same way) is in the Helper */
template<typename traits>
class CommonUsage {
public:
void use()
{
if (traits::getSize() > 0) {
typename traits::value_type value = traits::getValue();
}
}
};
int main()
{
CommonUsage<input_traits>().use();
CommonUsage<output_traits>().use();
CommonUsage<parameter_traits>().use();
}
B) Is this a good approach?
A. If i understood your question correctly you should use an abstract class.
Look at the next code, it essentially does the same as your code.
This is how i would do it.
#include <iostream>
template <typename value_type>
class Traits {
public:
virtual value_type getValue() const = 0;
virtual size_t getSize() const = 0;
virtual ~Traits() { }
};
class input_traits: public Traits <int>{
public:
virtual int getValue() const {
return 42;
}
virtual size_t getSize() const {
return 1;
}
};
class parameter_traits: public Traits <double>{
public:
virtual double getValue() const {
return 3.14;
}
virtual size_t getSize() const {
return 1;
}
};
class CommonUsage {
public:
template <typename value_type>
void use(const Traits<value_type>& traitsObject) {
if (traitsObject.getSize() > 0) {
std::cout << traitsObject.getValue();
}
}
};
int main() {
CommonUsage().use(parameter_traits());
return 0;
}
As an alternative to user's answer (this time using template specialization) is:
template <class T>
struct traits {
T getValue() const { throw std::runtime_exception("..."); }
size_t getSize() const { return 0; }
};
template <>
struct traits<int> {
int getValue() const { return 42; }
size_t getSize() const { return 1; }
};
template <>
struct traits<float> {
int getValue() const { return 3.145; }
size_t getSize() const { return 1; }
};
// do template aliasing
using input_traits = traits<int>;
using parameter_traits = traits<float>;
struct CommonUsage {
template <typename T>
static void use(const traits<T> &traits) {
if (traits.getSize() > 0)
std::cout << traits.getValue() << std::endl;
}
};
int main(int arg, char **argv) {
CommonUsage::use(input_traits());
CommonUsage::use(parameter_traits());
}
There are advantages/disadvantages to both approaches. If you use template specialization, you don't pay the overhead of virtual methods.