I haven't done any C++ programming for quite some time and I decided that I would mess around with it a little bit in my spare time so I decided to write me a little database program just for fun and I'm having trouble with creating an array of templated class objects.
What I have is this class which I want to use to represent a field in a database record.
template <class T, int fieldTypeId>
class Field
{
private:
T field;
int field_type;
public:
// ...
};
And I want to use an array of that class to represent a record in a database using this class.
class Database_Record
{
private:
int id;
Field record[];
public:
Database_Record(int);
Database_Record(int, Field[]);
~Database_Record();
};
Where I'm stuck at is the creation of the array in the Database_Record class since that is an array of templated class objects with each element possibly being of a different type and I'm not sure how I need declare the array because of that. Is what I'm trying to do even possible or am I going about it the wrong way? Any help would be greatly appreciated.
Field<T1> and Field<T2> are two completely different types. To treat them in a vector you need to generialize then somewhere. You may write AbstractField and
struct AbstractField{
virtual ~AbstractField() = 0;
};
template<class T,int fieldTypeId>
class Field: public AbstractField{
private:
T field;
public:
const static int field_type;
public:
virtual ~Field(){}
};
class Database_Record{
std::vector<AbstractField*> record;
public:
~Database_Record(){
//delete all AbstractFields in vector
}
};
and then keep a vector of AbstractField. also use vector instead of []. Use AbstractField* instead of AbstractField and write at least one pure virtual in AbstractField.
you may make the destructor of AbstractField pure virtual. and don't forget to delete all AbstractFields. in ~Database_Record()
You are going the wrong way.
Templates are used to create distinct types: std::vector<int> and std::vector<float> are distinct in much the same way (and as much) as int and float are.
Your syntax is also wrong; to create a dynamic array you'd put the following member in your Database_Record:
std::vector<Field> record; // if this was possible; however, it's not
To put several objects of distinct type into a single array, they ought to have a common base class.
In order to create an array of different types you need a base class for the objects and the array will be an array of pointers to that base class. So, for example,
class Field
{
public:
virtual ~Field() {}
virtual std::string toString() const = 0;
// and possibly other interface functions...
};
template <class T> FieldImpl : public Field
{
public:
virtual std::string toString() const
{
std::stringstream ss;
ss << val;
return ss.str();
}
// implementation of possibly other interface functions
private:
T val;
}
will be the types you need. The array will then be something like
std::vector<std::unique_ptr<Field>> my_array;
You can then do stuff with your array using the interface functions, e. g.
my_array[i]->toString();
As has been said before, C++ templates don't work like that.
At the same, using inheritance and vectors of pointers is not suitable for implementations of DB records because of performance limitations.
Take a step back and look at the problem in a more abstract way. As I understand from your code, the intent is to package an arbitrary number of fields of different types into a continuous memory block. Schematically:
struct DBRecord {
Type1 f1;
Type2 f2;
Type3 f3;
Type4 f4;
// etc...
}
You can achieve this by a bit ugly but practical construct consisting of an abstract template declaration and several specializations.
The declaration would look like this:
template <
typename T1,
typename T2 = void,
typename T3 = void,
typename T4 = void,
typename T5 = void,
typename T6 = void,
typename T7 = void,
typename T8 = void,
typename T9 = void,
typename T10 = void
> struct DBRecord;
It limits a max number of fields to some specific number obviously. If you need a truly arbitrary number of fields you need to switch to column-oriented paradigm.
Then, partial specializations should declare anatomy of structures for each number of arguments from 1 to 10:
template <
typename T1
> struct DBRecord <T1, void, void, void, void, void, void, void, void, void>
{
int id;
T1 f1;
DBRecord(int ID, T1 F1) {/*...*/};
};
template <
typename T1,
typename T2
> struct DBRecord <T1, T2, void, void, void, void, void, void, void, void>
{
int id;
T1 f1;
T2 f2;
DBRecord(int ID, T1 F1, T2 F2) {/*...*/};
};
// etc...
Now, you can allocate tables as arrays of records of certain types in one new[] call if you want.
And, you don't normally care about destruction of each field, since you free memory of the whole structure.
Macros can help to make declaration of such specializations somewhat more compact.
Consider every instantiation with a different template argument to be a different class. You either need to store a specific class (ie Field<int, 17>) or you need Field to have a non-templated base class which you can store in a list.
You can do something like this -
template <class T, int fieldTypeId>
class Field
{
private:
T field;
int field_Type;
};
template <class T, int fieldTypeId>
class Database_record
{
private:
int id;
std::vector<Field<T, fieldTypeId> > record_;
};
You are doing templates wrong. Instantiating class templates with
different types will yield two different types again with possibly
different sizes, which makes it impossible to store them in an array.
If you want to treat different types uniformly, use inheritance. And
when you use inheritance, don't use plain arrays, but vector or
std::array.
There is also a bunch of odd things in your code: Why store a
fieldTypeId when it is known statically? I guess it is related to
the type T you are using as a template parameter. Externalise the
mechanism through partial specializations:
template<typename T>
struct fieldTypeId;
template<>
struct fieldTypeId<int> {
const static int value = 0;
};
// etc....
If I'm completely wrong and you really know what you are doing: Use
type erasure through some any type (e.g. Boost.Any).
Made 2 example classes used for quick debug reports inspired by ToString() override of C#:
class UnknownType_t {
public:
virtual operator long&() { throw "Unsupported"; };
virtual operator const std::string() { throw "Unsupported"; };
virtual void Set(char*, long) = 0;
};
class Number : public UnknownType_t {
public:
Number(long _n) { n = _n; };
virtual operator long&() { return n; };
virtual void Set(char* buf, long size) {
n = 0;
memcpy(&n, buf, size);
}
long n;
};
class String : public UnknownType_t {
public:
String(const char *_s) : s(_s) {};
virtual operator const std::string() { return s; };
virtual void Set(char* buf, long size) {
s = std::string(reinterpret_cast<char*>(buf), size);
}
std::string s;
};
You can check type trying dynamic_cast, result in common array of UnknownType_t look like
{n=123 } or {s="ABC" }.
Base is not pure virtual by intent - required cross getters would have no sense...
Related
I have a class template, that creates a class with two members:
template<typename coordinateType, typename ...DataTypes>
class Object{
public:
std::tuple<coordinateType, coordinateType, coordinateType> position;
std::tuple<std::vector<DataTypes>...> plantData;
};
The issue is, rather than calling
auto myObject = Object<float, int, int, int>();
for an instance of Object with 3 ints of data, I want to clean this up and use two separate templates, without the unrelated "float" as the first argument.
Is there a way to implement this class so that it would be the equivalent of:
auto myObject = Object<float>();
myObject.track<int, int, int>();
And if not, is it possible to separate those two template arguments in any way, or am I stuck with grouping them together?
if you change the caller side a little, you can make track to return a new class.
template<typename T, typename...Us>
struct Object{
std::tuple<T, T, T> position;
std::tuple<std::vector<Us>...> plantData;
};
// you can also give it a different name, here I use a specialization instead
template<typename T>
struct Object<T>{
template<typename...Us>
Object<T,Us...> track();
};
void foo(){
auto myObjectCreator = Object<float>();
auto myObject = myObjectCreator.track<int, int, int>();
}
https://godbolt.org/z/qhPrEaa96
If I understand you correctly, you'd like track<Ts> to append Ts to the list of DataTypes. This can be achieved like:
template<typename coordinateType, typename ...DataTypes>
class Object{
public:
template<typename... Ts>
Object<coordinateType, ...DataTypes, Ts>
track() { return {}; } // you might add proper ctor call, element copy via tuple::cat, etc.
std::tuple<coordinateType, coordinateType, coordinateType> position;
std::tuple<std::vector<DataTypes>...> plantData;
};
As the title asks, how do I make a copy of a arbitrary type, but is different from the original type? As in, they are not implicitly convertible to each other but have the same interface.
I'll take cuda's pointers as an example to explain why this might be needed. Since host(CPU) and device(GPU) memory are separate, there is exactly 0 chance where you'd want to dereference a device pointer in host code. However, both are just plain old pointers, the compiler won't complain if you did actually do that. This is where type checking naturally fits in, these are all compile-time knowledge.
But then, to create a new pointer type, I'd have to manually type all the pointer arithmetic into a class to achieve this.
template<typename T>
class dptr
{
//...
dptr& operator++();
//...
auto& operator*();
//...
bool operator==(dptr) const;
//...
operator bool() const;
private:
T* ptr;
};
And the boilerplate gets worse when the type to be copied is even more complicated and when noexcept is sprinkled in.
What I'm looking for is basically what Go have: strong retyping of arbitrary types
type Int int
Int is now an int, with arithmetic and all that, but is not implicitly convertible to int. (Actually, what I want is more like Go's type embedding, if the reader knows what that is.)
I can think of couple of ways to do that. Both use strongly typed typedefs.
The first method assumes that you have the ability to define the main class, which can be a class template instead of a class.
template <typename Tag>
struct foo
{
void bar() {}
};
using Type1 = foo<int>;
using Type2 = foo<float>;
int main()
{
Type1 t1;
Type2 t2;
t1.bar(); // OK
t2.bar(); // OK
t2 = t1; // Incorrect.
}
The second method is similar but it uses existing classes. It assumes that you don't have the ability to modify the main class.
// Existing class.
struct foo
{
void bar() {}
};
// Bar can be used to create strongly typed typedefs.
template <typename Tag, typename Base>
struct Bar : public Base
{
};
using Type1 = Bar<int, foo>;
using Type2 = Bar<float, foo>;
int main()
{
Type1 t1;
Type2 t2;
t1.bar(); // OK
t2.bar(); // OK
t2 = t1; // Incorrect.
}
I have a (generated) set of classes that look roughly like this when simplified:
class A {
public:
static const int id = 0;
typedef int value_type;
void* data; // actually pointer to int
};
class B {
public:
static const int id = 1;
typedef float value_type;
void* data; // actually pointer to float
};
There are altogether tens of these, with much fewer types. I need to create classes that calculate some derived values for all of these. Now the obvious solution would be using a template like this:
template<class T>
class Derived {
public:
typename T::value_type value;
void update(const void* data) {
value = *static_cast<typename T::value_type*>(data);
// do some calculations
}
};
But this is going to instantiate a separate class for every single parameter class A, B, and so on; most of which will be identical. The other solution would be an obvious template class like this:
template<typename T>
class Derived2 {
public:
T value;
void update(const void* data) {
value = *static_cast<T*>(data);
}
};
This would be updating the code using this class manually if the schema that classes A, B, etc., are generated from changes. Is there a way to use the value_type typedefs to generate instantiations of Derived2<int>, Derived2<float> etc., or at least match the types of manually parametrized instantiations to types A, B, etc.?
This is an embedded system, so the target is reducing the amount of identical code, even if it leads to more convoluted C++ code. Replacing the void*s with actual types would lead to code explosion in other parts of the program, so it is not done.
As posted in the comments this will do what you need:
template<class T> struct Derived : Derived2<typename T::value_type> { };
I am trying to set the type of the member of a class, without passing it through template argument.
In details:
// Forward declaration:
class A;
class B;
class Base
{
};
template <class T>
class Derived : public Base
{
private:
T2 var;
};
where T could be either class A or class B.
What I would like to do is for Derived<A> T2 is int (for instance) and for Derived<B> T2 is double (for instance). I would like to avoid the following solution:
template <class T1, class T2>
class Derived : public Base
{
private:
T2 var;
};
I want to avoid this because for Derived<A> there could be various possible combinations for T2: Derived<A,int>, Derived<A,double>, ...
What I want is that the type of T2 is unique for the entire Derived<A>.
Any idea how to solve that ?
Update: The comments show that the original problem you are trying to solve is not completely explained in the question. I'll leave the original answer nevertheless at the bottom of this answer.
You cannot have two Derived<A> with different types T2 for the var member. In addition, a variable defined by the User can not influence the type of the member variable. Variable values are set at runtime, types are determined at compiletime.
To store a type somehow defined by the user, you will have either have to restrict the variable to a set of known types or use one type that contains a serialized version of the variable's content. The set of known types is often used in the context of databases, where the fields can have one of several predefined types (e.g. String, Integer, Boolean, Double). The type for the member variable then could be a Boost.Variant, restricted to C++ representations of that type. Another application of "user defined types" are where the user of your program has to somehow define the layout and interpretation of the type and its object, for example if your program is the interpreter of some scripting language. In that case again a Boost.Variant (or something similar) can be of use, or, since the value is probably some user provided input, just store the serialized value in a string and interpret it every time you have to deal with it.
Original answer:
This is usually done via template metaprogramming, in this case a type function (sometimes, depending on the context, part of a traits or policy class):
template <class T>
struct DerivedMemVarType {
typedef double type; //default
};
template<>
struct DerivedMemVarType<A> {
typedef int type;
};
And then:
template <class T>
class Derived : public Base
{
typedef typename DerivedMemVarType<T>::type T2;
private:
T2 var;
};
You can also leave out the default, so that any instantiation of Derived for a type that you have not mapped in your function will give a compile error:
template <class T>
struct DerivedMemVarType; //default is not defined
template<>
struct DerivedMemVarType<A> {
typedef int type;
};
template<>
struct DerivedMemVarType<B> {
typedef double type;
};
//...
Derived<C> dc; // ...template error mess....
// --> error: invalid use of incomplete type 'struct DerivedMemVarType<C>'
if you do not have any type specific function call, you can use something like...
class A;
class B;
class Base
{
};
template <class T>
class Derived : public Base
{
public:
Derived(T startVal):var(startVal){}
private:
T var;
};
template <typename T>
Derived<T> MakeDerived(T initValue)
{
return Derived<T>(initValue);
}
and now you can use it the following and the compiler should know what type you are passing to the function.
int initialValue = 0;
auto derived = MakeDerived(initialValue);
I think you can create a separate class that just holds a typedef which you then specialize and use in your Derived class.
template<typename T>
class VarType {
public:
typedef int TheType;
}
template <>
class VarType<B> {
public:
typedef double TheType;
};
template <typename T>
class Derived : public Base {
private:
typename VarType<T>::TheType var;
};
Consider the following contrived example of a templated array definition:
template <typename t, unsigned int n> class TBase
{
protected:
t m_Data[n];
//...
};
template <typename t, unsigned int n> class TDerived : public TBase<t, n>
{
TDerived()
{
}
};
I can specialize this type to provide a non-default constructor for an array of length 2 as follows:
template <typename t> class TDerived<t, 2> : public TBase<t, 2>
{
public:
TDerived(const t& x0, const t& x1)
{
m_Data[0] = x0;
m_Data[1] = x1;
}
};
int main()
{
TDerived<float, 2> Array2D_A(2.0f, 3.0f); //uses specialised constructor
TDerived<float, 3> Array3D_A; //uses default constructor
return 0;
}
Is there some other way I can create a class that has different constructor options constrained against template parameters at compile-time without the requirement for a complete class specialisation for each variation?
In other words, is there some way I can have specialised constructors in the TBase class without the need for the intermediary step of creating TDerived whilst preserving the functionality of TBase?
I think deriving your class from a base class is not relevant to the question here, that's a mere implementation detail. What you really seem to be after is if there's a way to partially specialize member functions, like the constructor. Do you want something like this?
template <typename T, int N> class Foo
{
Foo(); // general
template <typename U> Foo<U, 2>(); // specialized, NOT REAL CODE
};
This doesn't work. You always have to specialize the entire class. The reason is simple: You have to know the full type of the class first before you even know which member functions exist. Consider the following simple situation:
template <typename T> class Bar
{
void somefunction(const T&);
};
template <> class Bar<int>
{
double baz(char, int);
};
Now Bar<T>::somefunction() depends on T, but the function only exists when T is not int, because Bar<int> is an entirely different class.
Or consider even another specialization template <> class Bar<double> : public Zip {}; -- even the polymorphic nature of a class can be entirely different in a specialization!
So the only way you can provide specializations new declarations of members, including constructors, is by specializing the entire class. (You can specialize the definition of existing functions, see #Alf's answer.)
There are basically two options I see for this:
Use a variadic function for construction (ie. "..." notation), you can use the value n inside that function to get your arguments from the stack. However, the compiler will not check at compile time if the user provides the correct number of arguments.
Use some serious template magic to allow a call chaning initialization, that would look like this: vector(2.0f)(3.0f). You can actually build something that at least ensures the user does not provide too many arguments here. However tha mechanism is a little more involved, I can assemble an example if you want.
You can always specialize a member, e.g.
#include <stdio.h>
template< class Type >
struct Foo
{
void bar() const
{ printf( "Single's bar.\n" ); }
};
template<>
void Foo< double >::bar() const
{ printf( "double's bar.\n" ); }
int main()
{
Foo<int>().bar();
Foo<double>().bar();
}
But you want effectively different signatures, so it's not directly a case of specializing a member.
One way forward is then to declare a constructor with a single argument, of a type dependent on the template parameters.
Then you can specialize that, as you want.
Cheers & hth.,
Since constructor is a function, you need to fully specialize the containing class to address your specific problem. No way out.
However, functions cannot be partially specialized (in all compilers). So suppose if you know that you need n = 2 when t = int or double then following is one alternative.
template<>
TDerived<int,2>::TDerived()
{
//...
}
template<>
TDerived<double,2>::TDerived()
{
//...
}
and so on.
[Note: If you use MSVC, then I think it supports partial specialization; in that case you can try:
template<typename t>
TDerived<t,2>::TDerived()
{
//...
}
though, I am not sure enough for that.]
You could give the most common definitions in the non-specialized class and static_assert (BOOST_STATIC_ASSERT for non C++0x) on the array length. This could be considered a hack but is a simple solution to your problem and safe.
template<typename T, unsigned int n>
struct Foo {
Foo(const T& x) { static_assert(n == 1, "Mooh!"); }
Foo(const T& x1, const T& x2) { static_assert(n == 2, "Mooh!"); }
};
The "evil" way would be variadic arguments.
template<typename T, unsigned int n>
struct Foo {
Foo(...) {
va_list ap;
va_start(ap, n);
for(int j=0; j < n; ++j)
bork[j] = va_arg(ap, T);
va_end(ap);
}
};
Then there is also C++0x and the good old make_something trick which is more difficult then one would think.
template<typename... T, unsigned int n>
Foo<T, n> make_foo(T&&...) {
// figure out the common_type of the argument list
// to our Foo object with setters or as a friend straight to the internals
Foo< std::common_type< T... >::type, sizeof(T) > foo;
// recursive magic to pick the list apart and assign
// ...
return foo;
}