Hello again.
I am currently using a base class for a certain type of object, which looks like this:

#include <vector>

template <class T>
class CObject
{
	public:
		inline virtual ~CObject () { }
		virtual std::vector<T> *Output (std::vector<int> *Input) = 0;
};

The problem, that arises from this contraption is, that, in order to have some objects working in double precision and some in single precision, the pointer type from one object to another cannot be defined. At the moment, I am using a pointer of void type and an enum PRECISION with two values: PRECISION_DOUBLE and PRECISION_SINGLE. The function calls look like this:

std::pair<void*, PRECISION> SomeObject;
switch (SomeObject.second)
{
	case PRECISION_DOUBLE:
		((CObject<double>*) SomeObject.second)->Output (...);
	case PRECISION_SINGLE:
		((CObject<float>*) SomeObject.second)->Output (...);
}

If I wrote a second enumeration, one for object type, I could do all of this without a single inheritance, but if I wanted that, I would be writing in C not in C++.
So now, I am looking for different methods to achieve this.
One idea, that came to my mind was the implementation of a converter object, which would look like this:

#include <vector>

template <class T>
class CConvert : public CObject<T>
{
	private:
		void *Input;
		std::vector<T> m_Output;
	public:
		std::vector<T> *Output (std::vector<int> *Input);
};

std::vector<double> *CConvert<double>::Output (std::vector<int> *Input)
{
	std::vector<float> *InputVector = ((CObject<float>*) Input)->Output (std::vector<int> *Input);
	m_Output.clear ();
	for (std::vector<float>::iterator i = InputVector->begin (); i != Input->end (); i++)
		m_Output.push_back (*i);
	return &m_Output;
}

std::vector<float> *CConvert<float>::Output (std::vector<int> *Input)
{
	std::vector<double> *InputVector = ((CObject<double>*) Input)->Output (std::vector<int> *Input);
	m_Output.clear ();
	for (std::vector<double>::iterator i = InputVector->begin (); i != Input->end (); i++)
		m_Output.push_back (*i);
	return &m_Output;
}

The problem with this approach would be, that, whenever a CObject<double> needs to be connected to a CObject<float>, a CConvert<double> would have to be put in between.
Any other solutions are very appreciated.

Greetings,
JaR

Recommended Answers

All 6 Replies

There isn't really any clean solution.

Remember, a template class is an incomplete type. It is only when you parameterize it that it becomes a complete, concrete, usable, valid type.

So vector <> * pvec_of_anything; just can't work. Such a type doesn't exist.

However, vector <int> * pvec_of_int; is a complete type.
As is vector <double> * pvec_of_double; . The obvious problem is that double and int are distinct types, so vectors of them are also distinct types. There is really no way of getting around that using generic programming --that isn't the problem it was intended to solve.

A common answer is to use a union and implement a "variant" datatype. Or, if you just have a special need, add a tag field to your container class that identifies the type of T.

Alas, sorry there isn't a simpler answer.

the typical work around (as exemplified by the standard library containers and function objects) is to have the generic type announce dependent types via suitable typedefs.

#include <vector>
#include <iostream>
#include <typeinfo>

template <class T>
class CObject
{
  public:
    typedef T numeric_type ;
    typedef std::vector<T>* output_type ;

    inline virtual ~CObject () { }
    virtual output_type Output( const std::vector<int>* Input ) = 0 ;
};

template< typename T >
typename T::output_type function( T& object,
                                  const std::vector<int>* input )
{
  typedef typename T::output_type result_type ;
  std::cout << "result type is " << typeid(result_type).name() << '\n' ;
  result_type result = object.Output( input ) ;
  return result ;
}

Remember, a template class is an incomplete type. It is only when you parameterize it that it becomes a complete, concrete, usable, valid type.

Of course. I was hoping, there would be a solution like using a class as a datatype, which would then hold floats as well as doubles or something like that.

So vector <> * pvec_of_anything; just can't work. Such a type doesn't exist.

That's, why I was using void*.

A common answer is to use a union and implement a "variant" datatype.

But then, every variable would cost 64 bits of memory, which is one of the things, I am trying to avoid. I think, I will stick to using pairs of void* and enum PRECISION.
Maybe, I will define an inline function, that holds the switch statement.

Greetings,
JaR

you can try this approach that at least compiles

class COutput{
public:
  virtual void Handle() = 0;
  virtual ~COutput(){}
};

class CSingleOutput:public COutput{
private:
  //eg.
  std::vector<float>* seed; 
public:
  CSingleOutput(const std::vector<float>& s){
    // you can run the code for handle the output or assing to seed the address of s 
    // or create a new vector<float> from s or whatever;
  }
  
  //eg.
  virtual void Handle(){
    // do some stuff whit your output
  }
  
};

class CDoubleOutput:public COutput{
private:
  //eg.
  std::vector<double>* seed; 
public:
  CDoubleOutput(const std::vector<double>& s){
    // you can run the code for handle the output or assing to seed the address of s 
    // or create a new vector<double> from s or whatever;
  }
  
  //eg.
  virtual void Handle(){
    // do some stuff whit your output
  }
  
};


class CObject{
public:
  virtual ~CObject () { }
  virtual COutput *Output(std::vector<int> *Input) = 0;
};


class CDouble:public CObject{
public:
  inline virtual ~CDouble(){ }
  virtual COutput *Output (std::vector<int> *Input){
    std::vector<double>* vect;
    //generate vec here;
    return new CDoubleOutput(*vect);
  }
};

class CSingle:public CObject{
public:
  inline virtual ~CSingle(){ }
  virtual COutput *Output (std::vector<int> *Input){
    std::vector<float>* vect;
    //generate vec here;
    return new CSingleOutput(*vect);
  }
};

and write the other code as

std::pair<void*, PRECISION> SomeObject;
SomeObject.second()->Output(...).Handle();

I thought of deriving double and single classes from one common base class before, but there is simply no way, that it will give me the flexibility of templates. I am going to write a private inline member function in CObject, that handles the function calls to other objects. Combined with some typedefs, that will be propably be the easiest and most comforatble way. Thank you for your ideas, I apreciate your help.

Greetings,
JaR

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.