I'm playing around with templates. I'm not trying to reinvent the std::vector, I'm trying to get a grasp of templateting in C++.
Can I do the following?
template <typename T>
typedef struct{
size_t x;
T *ary;
}array;
What I'm trying to do is a basic templated version of:
typedef struct{
size_t x;
int *ary;
}iArray;
It looks like it's working if I use a class instead of struct, so is it not possible with typedef structs?
The problem is you can't template a typedef, also there is no need to typedef structs in C++.
The following will do what you need
template <typename T>
struct array {
size_t x;
T *ary;
};
template <typename T>
struct array {
size_t x;
T *ary;
};
You don't need to do an explicit typedef for classes and structs. What do you need the typedef for? Further, the typedef after a template<...> is syntactically wrong. Simply use:
template <class T>
struct array {
size_t x;
T *ary;
} ;
You can template a struct as well as a class. However you can't template a typedef. So template<typename T> struct array {...}; works, but template<typename T> typedef struct {...} array; does not. Note that there is no need for the typedef trick in C++ (you can use structs without the struct modifier just fine in C++).
The Standard says (at 14/3. For the non-standard folks, the names following a class definition body (or the type in a declaration in general) are "declarators")
In a template-declaration, explicit specialization, or explicit instantiation the init-declarator-list in the dec-laration shall contain at most one declarator. When such a declaration is used to declare a class template, no declarator is permitted.
Do it like Andrey shows.
From the other answers, the problem is that you're templating a typedef. The only "way" to do this is to use a templated class; ie, basic template metaprogramming.
template<class T> class vector_Typedefs {
/*typedef*/ struct array { //The typedef isn't necessary
size_t x;
T *ary;
};
//Any other templated typedefs you need. Think of the templated class like something
// between a function and namespace.
}
//An advantage is:
template<> class vector_Typedefs<bool>
{
struct array {
//Special behavior for the binary array
}
}
The syntax is wrong. The typedef should be removed.
Looks like #monkeyking is trying it to make it more obvious code as shown below
template <typename T>
struct Array {
size_t x;
T *ary;
};
typedef Array<int> iArray;
typedef Array<float> fArray;
Related
I am trying to do a forward declaration of a struct in c++ that has a typename. Something like this is entirely valid:
typedef struct foo foo;
struct foo{
int f;
};
My struct just instead has a typename, so I tried this:
template <typename T>
typedef struct mV<T> mV;
template <typename T>
struct mV{
//contents of struct
};
However, I then get the errors a typedef cannot be a template, explicit specialization of undeclared template struct and redefinition of 'mV' as different kind of symbol. How can I go about fixing that?
You're describing a forward- declaration . (A future is something completely different in modern C++).
typedef aliasing structure tags is not needed, and rarely desired, in C++. Instead you simply declare the class type and be done with it.
// typedef struct mV mV; // not this
struct mV; // instead this
The same goes for templates
template<class T>
struct mV;
If you need/want to attach an alias to your template type, you still can do so via using
template<class T>
struct mV;
template<class T>
using MyAliasNameHere = mV<T>;
Armed with all of that, and heading off what I surmise you'll be discovering in short order, you'll probably need to read this as well: Why can templates only be implemented in header files?. Something tells me that's about to become highly relevant.
Problem
Consider the following class
template <typename T>
struct A
{
T x;
};
Now, another class is templated like so:
template <typename T, typename U>
class B
{
protected:
std::vector<U> arr;
public:
T get_x(unsigned int p) { return arr[p].x; }
};
I would like to access the field A<T>::x from within B<T, A<T>>::get_x() and return it unaltered (i.e., keep its type as T). My poor knowledge of templating says that this requires knowing the type andof T it should be one of the template parameters of class B. However, that makes it possible to declare something inconsistent, like B<int, A<double>>, and in general sounds like an unnecessary repetition.
Questions
Is what I wrote an example of bad programming practice? How should this be written?
Is there a possibility of inferring the type T of A<T>::x and avoid two template types? It feels like a repetition, so I am not sure if there is a God-fearing, standard-abiding solution out there or not.
For what it is worth, I am using GCC 4.6.2 with -std=c++0x.
I would suggest an approach adopted by the Standard Library. Define a nested type.
template <typename T>
struct A
{
typedef T value_type; //this is nested type to be used by B
T x;
};
//this is another class added by me, just to demonstrate the genericity
template <typename T>
struct C
{
typedef T value_type; //this is nested type to be used by B
T x;
};
template <typename T>
class B
{
typedef typename T::value_type value_type; //get the nested type
protected:
std::vector<T> arr;
public:
value_type get_x(unsigned int p) { return arr[p].x; }
//^^^^^^^^^ note this
};
Usage:
B<A<int>> ba; //'>>' if C++11, otherwise use '> >' (separate them by space)
B<C<double>> bc; //works for C class template as well
In C++ library headers, we'll sometimes see the following to improve legibility of the code inside a class:
template<typename MyExplicitelyLongTemplateParameter>
class C
{
public:
typedef MyExplicitelyLongTemplateParameter P;
// Use "P" and keep your sanity.
};
My question is, can one do the same with template template parameter?
template<template<typename> typename MyExplicitelyLongTemplateParameter>
class C
{
public:
typedef /* ??? */ P;
// Use "P" and keep your sanity.
};
You can't create a typedef, no, but you can shorten the name:
template <template <typename> typename MyExplicitlyLongTemplateParameter>
class C
{
public:
template <typename T>
struct P
{
typedef MyExplicitlyLongTemplateParameter<T> Type;
};
// Use "P<T>::Type" and keep your sanity.
};
In the current standard, you can't typedef a template. In the new, upcoming standard, you will be able to....
typedef boost::interprocess::managed_shared_memory::segment_manager
segment_manager_t; // Works fine, segment_manager is a class
typedef boost::interprocess::adaptive_pool
allocator_t; // Can't do this, adaptive_pool is a template
The idea is that if I want to switch between boost interprocess' several different options for shared memory and allocators, I just modify the typedefs. Unfortunately the allocators are templates, so I can't typedef the allocator I want to use.
Is there a way to achieve an alias to a template in C++? (Except for the obvious #define ALLOCATOR_T boost::interprocess::adaptive_pool)
Yes, (if I understand your question correctly) you can "wrap" the template into a struct like:
template<typename T>
class SomeClass;
template<typename T>
struct MyTypeDef
{
typedef SomeClass<T> type;
};
and use it as:
MyTypeDef<T>::type
Edit: C++0x would support something like
template<typename T>
using MyType = SomeClass<T>;
Edit2: In case of your example
typedef boost::interprocess::adaptive_pool allocator_t;
can be
template<typename T>
struct allocator_t
{
typedef boost::interprocess::adaptive_pool<T> type;
}
and used as
allocator_t<SomeClass>::type
C++ doesn't support this, though it is slated to be fixed in the new standard. You might get away with deriving a new class template from adaptive_pool if there are no non-trivial constructors (or if you're happy to write a few forwarding constructors).
template <class T>
class allocator_t : public adaptive_pool<T> {
public:
// Just making up a forwarding constructor as an example. I know nothing
// anything about adaptive_pool.
allocator_t(int arg1, float arg2) : adaptive_pool<T>(arg1, arg2) { }
};
EDIT: Forget this answer. My vote goes to #Akanksh.
I have a matrix class and a column class inside it:
template<class T>
struct MatrixT
{
template<class T>
struct ColumnT
{
};
};
Note that a ColumnT will always hold the same type as a MatrixT.
For convenience I define
typedef MatrixT<double> matrix;
Since in reality, I'll be using a double element most of the time. But I also want to define something similar for the columnT class. I tried
typedef MatrixT<double>::ColumnT<double> matrix::column;
but compilation fails with the error
Error - qualified name is not allowed
Is there a way of achieving what I want?
I'd like to be able to type matrix::column c; just as I can type matrix m;
Just remove the second template<class T>
template<class T>
struct MatrixT
{
struct ColumnT
{
};
};
ColumnT should then be using the same type as MatrixT, and your typedef...
typedef MatrixT<double> matrix;
...should work as you are expecting it to.