Parameterized typedef possible? - c++

I was wondering if it is possible to have some kind of parameterized typedef.
To illustrate, in my code I use this typedef:
typedef std::queue<std::vector<unsigned char>, std::deque<std::vector<unsigned char> > > UnsignedCharQueue;
As you can see this is a rather unwieldy construct so the typedef makes sense. However, if I want to have queues with other datatypes I need to define them beforehand explizitly.
So I was thinking if it were possible to use a construct like this:
typedef std::queue<std::vector<T>, std::deque<std::vector<T> > > Queue<T>;
private:
Queue<unsigned char> mMyQueue;
Similar like generics in Java.

In C++11, you can use template aliases, such as in:
template<typename T>
using my_alias = some_class_template<T>;
// ...
my_alias<T> obj; // Same as "some_class_template<T> obj;"
So in your case it would be:
template<typename T>
using Queue = std::queue<std::vector<T>, std::deque<std::vector<T> > >;
Also notice, that in C++11 you do not need to leave a space between closed angle brackets, so the above can be rewritten as follows:
template<typename T>
using Queue = std::queue<std::vector<T>, std::deque<std::vector<T>>>;
// ^^^
In C++03 you could define a Queue metafunction this way:
template<typename T>
struct Queue
{
typedef std::queue<std::vector<T>, std::deque<std::vector<T> > > type;
};
Which you would then use this way:
Queue<int>::type obj;
If you are using it in a template with parameter T (as in the following), do not forget the typename disambiguator:
template<typename T>
struct X
{
typename Queue<T>::type obj;
// ^^^^^^^^
}

Yes, it works like this:
template <typename T> using Queue = std::queue<std::vector<T>, std::deque<std::vector<T> > >;

Related

How to reduce any compound to non-compound type

Requirement: Given the compound type 'T', what is the non-compound type used as a base type?
So far my attempt is this template alias:
template <class T>
using reduce_to_non_compound_t =
std::remove_all_extents_t<
std::remove_pointer_t<
std::remove_cvref_t < T >
> >;
for example
// array of pointers to string
using arr_of_sp = std::string * (&)[42];
// should pass
static_assert( std::is_same_v<
std::string,
reduce_to_non_compound_t<arr_of_sp>
> )
A number of use cases to test this is probably very large. Before I go any further with this, I would like to ask if anybody has any better idea or even implementation?
I am asking if such a thing is logical. This is where use cases are coming in. If it is logical then it can be written.
If, as you say, you simply want to strip cv-qualifiers, pointers, references and extents from a type, then you can use this:
template <typename T, typename = void> struct base {using type = std::remove_cv_t<T>;};
template <typename T> using base_t = typename base<T>::type;
template <typename T> struct base<T, std::enable_if_t<std::is_array_v<T>>>
{using type = base_t<std::remove_all_extents_t<T>>;};
template <typename T> struct base<T, std::enable_if_t<std::is_reference_v<T>>>
{using type = base_t<std::remove_reference_t<T>>;};
template <typename T> struct base<T, std::enable_if_t<std::is_pointer_v<T>>>
{using type = base_t<std::remove_pointer_t<T>>;};
Usage:
static_assert(std::is_same_v<int, base_t<const int *volatile[4]>>);
It can be easily extended to work with member function pointers, functions, or something else.
I might humbly report, my suggested (in the question) solution actually works.
Special thanks to Mr Holy Black Cat, who spotted a flaw, so I added 'dbj::remove_all_ptr_t`. Now solution now works for double, triple etc pointers too.
Wandbox is here
namespace dbj
{
template <typename T> struct remove_all_ptr { typedef T type; };
template <typename T> struct remove_all_ptr<T*> {
using type = typename remove_all_ptr<std::remove_cv_t<T>>::type;
};
template <typename T>
using remove_all_ptr_t = typename remove_all_ptr<T>::type ;
template< class T >
struct remove_cvref {
typedef std::remove_cv_t<std::remove_reference_t<T>> type;
};
template< class T >
using remove_cvref_t = typename remove_cvref<T>::type;
template <class T>
using to_base_t =
remove_all_ptr_t< std::remove_all_extents_t< remove_cvref_t < T > > >;
} // dbj
Mr Holy Black Cat solution works too. Although some might find it a bit complicated (I personally think it is not).
My solution is in the namespace dbj and his is in a namespace hbc. This is my quick test.
// testing
static_assert(std::is_same_v<std::string, hbc::base_t<std::string * (&)[42]>>);
static_assert(std::is_same_v<std::string ,dbj::to_base_t<std::string * (&)[42]>>);
static_assert(std::is_same_v<void (), hbc::base_t<void ()>>);
static_assert(std::is_same_v<void (), dbj::to_base_t<void ()>>);
//
struct X { char data{}; char method () const { return {};} };
static_assert(std::is_same_v<X, hbc::base_t<X (&) []>>);
static_assert(std::is_same_v<X, dbj::to_base_t<X (&) []>>);
//
using method_t = char (X::*)() ;
static_assert(std::is_same_v<method_t, hbc::base_t< method_t (&) []>>);
static_assert(std::is_same_v<method_t, dbj::to_base_t< method_t (&) []>>);
Both solutions are passing the tests above. Wandbox is here.
Thank you all for the valuable discussion.

Default values in templates with template arguments ( C++ )

Assume I have a template (called ExampleTemplate) that takes two arguments: a container type (e.g. list, vector) and a contained type (e.g. float, bool, etc). Since containers are in fact templates, this template has a template param. This is what I had to write:
#include <vector>
#include <list>
using namespace std;
template < template <class,class> class C, typename T>
class ExampleTemplate {
C<T,allocator<T> > items;
public:
....
};
main()
{
ExampleTemplate<list,int> a;
ExampleTemplate<vector,float> b;
}
You may ask what is the "allocator" thing about. Well, Initially, I tried the obvious thing...
template < template <class> class C, typename T>
class ExampleTemplate {
C<T> items;
};
...but I unfortunately found out that the default argument of the allocator...
vector<T, Alloc>
list<T, Alloc>
etc
...had to be explicitely "reserved" in the template declaration.
This, as you can see, makes the code uglier, and forces me to reproduce the default values of the template arguments (in this case, the allocator).
Which is BAD.
EDIT: The question is not about the specific problem of containers - it is about "Default values in templates with template arguments", and the above is just an example. Answers depending on the knowledge that STL containers have a "::value_type" are not what I am after. Think of the generic problem: if I need to use a template argument C in a template ExampleTemplate, then in the body of ExampleTemplate, do I have to reproduce the default arguments of C when I use it? If I have to, doesn't that introduce unnecessary repetition and other problems (in this case, where C is an STL container, portability issues - e.g. "allocator" )?
Perhaps you'd prefer this:
#include <vector>
#include <list>
using namespace std;
template <class Container>
class ForExamplePurposes {
typedef typename Container::value_type T;
Container items;
public:
};
int main()
{
ForExamplePurposes< list<int> > a;
ForExamplePurposes< vector<float> > b;
}
This uses "static duck typing". It is also a bit more flexible as it doesn't force the Container type to support STL's Allocator concept.
Perhaps using the type traits idiom can give you a way out:
#include <vector>
#include <list>
using namespace std;
struct MyFunkyContainer
{
typedef int funky_type;
// ... rest of custom container declaration
};
// General case assumes STL-compatible container
template <class Container>
struct ValueTypeOf
{
typedef typename Container::value_type type;
};
// Specialization for MyFunkyContainer
template <>
struct ValueTypeOf<MyFunkyContainer>
{
typedef MyFunkyContainer::funky_type type;
};
template <class Container>
class ForExamplePurposes {
typedef typename ValueTypeOf<Container>::type T;
Container items;
public:
};
int main()
{
ForExamplePurposes< list<int> > a;
ForExamplePurposes< vector<float> > b;
ForExamplePurposes< MyFunkyContainer > c;
}
Someone who wants to use ForExamplePurposes with a non-STL-compliant container would need to specialize the ValueTypeOf traits class.
I would propose to create adapters.
Your class should be created with the exact level of personalization that is required by the class:
template <template <class> C, template T>
class Example
{
typedef T Type;
typedef C<T> Container;
};
EDIT: attempting to provide more is nice, but doomed to fail, look at the various expansions:
std::vector<T>: std::vector<T, std::allocator<T>>
std::stack<T>: std::stack<T, std::deque<T>>
std::set<T>: std::set<T, std::less<T>, std::allocator<T>>
The second is an adapter, and so does not take an allocator, and the third does not have the same arity. You need therefore to put the onus on the user.
If a user wishes to use it with a type that does not respect the expressed arity, then the simplest way for him is to provide (locally) an adapter:
template <typename T>
using Vector = std::vector<T>; // C++0x
Example<Vector, bool> example;
I am wondering about the use of parameter packs (variadic templates) here... I don't know if declaring C as template <class...> C would do the trick or if the compiler would require a variadic class then.
You have to give the full template signature, including default parameters, if you want to be able to use the template template parameter the usual way.
template <typename T, template <class U, class V = allocator<U> > class C>
class ExampleTemplate {
C<T> items;
public:
....
};
If you want to handle other containers that the one from the STL, you can delegate container construction to a helper.
// Other specialization failed. Instantiate a std::vector.
template <typename T, typename C>
struct make_container_
{
typedef std::vector<T> result;
};
// STL containers
template <typename T, template <class U, class V = allocator<U> > class C>
struct make_container_<T,C>
{
typedef C<T> result;
};
// Other specializations
...
template <typename T, typename C>
class ExampleTemplate {
make_container_<T,C>::result items;
public:
....
};
I think, it is required to reproduce all template parameters, even default. Note, that Standard itself does not use template template parameters for containter adaptors, and prefers to use regular template parameters:
template < class T , class Container = deque <T > > class queue { ... };
template < class T , class Container = vector <T>, class Compare = less < typename Container :: value_type > > class priority_queue { ... };
The following code will allow you to do something like you're asking for. Of course, this won't work with standard containers, since this has to already be part of the template class that's being passed into the template.
/* Allows you to create template classes that allow users to specify only some
* of the default parameters, and some not.
*
* Example:
* template <typename A = use_default, typename B = use_default>
* class foo
* {
* typedef use_default_param<A, int> a_type;
* typedef use_default_param<B, double> b_type;
* ...
* };
*
* foo<use_default, bool> x;
* foo<char, use_default> y;
*/
struct use_default;
template<class param, class default_type>
struct default_param
{
typedef param type;
};
template<class default_type>
struct default_param<use_default, default_type>
{
typedef default_type type;
};
But I don't really think this is what you're looking for. What you're doing with the containers is unlikely to be applicable to arbitrary containers as many of them will have the problem you're having with multiple default parameters with non-obvious types as defaults.
As the question exactly described the problem I had in my code (--I'm using Visual Studio 2015), I figured out an alternative solution which I wanted to share.
The idea is the following: instead of passing a template template parameter to the ExampleTemplate class template, one can also pass a normal typename which contains a type DummyType as dummy parameter, say std::vector<DummyType>.
Then, inside the class, one replace this dummy parameter by something reasonable. For replacement of the typethe following helper classes can be used:
// this is simply the replacement for a normal type:
// it takes a type T, and possibly replaces it with ReplaceByType
template<typename T, typename ReplaceWhatType, typename ReplaceByType>
struct replace_type
{
using type = std::conditional_t<std::is_same<T, ReplaceWhatType>::value, ReplaceByType, T>;
};
// this sets up the recursion, such that replacement also happens
// in contained nested types
// example: in "std::vector<T, allocator<T> >", both T's are replaced
template<template<typename ...> class C, typename ... Args, typename ReplaceWhatType, typename ReplaceByType>
struct replace_type<C<Args ...>, ReplaceWhatType, ReplaceByType>
{
using type = C<typename replace_type<Args, ReplaceWhatType, ReplaceByType>::type ...>;
};
// an alias for convenience
template<typename ... Args>
using replace_type_t = typename replace_type<Args ...>::type;
Note the recursive step in replace_type, which takes care that types nested in other classes are replaced as well -- with this, for example, in std::vector<T, allocator<T> >, both T's are replaced and not only the first one. The same goes for more than one nesting hierarchy.
Next, you can use this in your ExampleTemplate-class,
struct DummyType {};
template <typename C, typename T>
struct ExampleTemplate
{
replace_type_t<C, DummyType, T> items;
};
and call it via
int main()
{
ExampleTemplate<std::vector<DummyType>, float> a;
a.items.push_back(1.0);
//a.items.push_back("Hello"); // prints an error message which shows that DummyType is replaced correctly
ExampleTemplate<std::list<DummyType>, float> b;
b.items.push_back(1.0);
//b.items.push_back("Hello"); // prints an error message which shows that DummyType is replaced correctly
ExampleTemplate<std::map<int, DummyType>, float> c;
c.items[0]=1.0;
//c.items[0]="Hello"; // prints an error message which shows that DummyType is replaced correctly
}
DEMO
Beside the not-that-nice syntac, this has the advantage that
It works with any number of default template parameters -- for instance, consider the case with std::map in the example.
There is no need to explicitly specify any default template parameters whatsoever.
It can be easily extended to more dummy parameters (whereas then it probably should not be called by users ...).
By the way: Instead of the dummy type you can also use the std::placeholder's ... just realized that it might be a bit nicer.

Templates and STL

The following code represents a container based on std::vector
template <typename Item>
struct TList
{
typedef std::vector <Item> Type;
};
template <typename Item>
class List
{
private
typename TList <Item>::Type items;
....
}
int main()
{
List <Object> list;
}
Is it possible to templatize std::vector and create a general container, something like that?
template <typename Item, typename stl_container>
struct TList
{
typedef stl_container<Item>;
};
where stl_container represents std::vector, std::list, std::set...? I would like to choose the type of container at the time of the creation.
List <Object, std::vector> list; //vector of objects, not a real code
List <Object, std::vector> list; //list of objects, not a real code
Thanks for your answers...
Updated question:
I tried the following code but there are errors:
#include <vector>
template <typename Item, typename Container>
struct TList
{
typedef typename Container <Item>::type type; //Error C2059: syntax error : '<', Error C2238: unexpected token(s) preceding ';
};
template <typename T>
struct vector_container
{
typedef std::vector<T> type;
};
int _tmain(int argc, _TCHAR* argv[])
{
TList <int, vector_container> v;
TList <int, map_container> m;
}
Yes, but not directly:
template <typename Item, template <typename> class Container>
struct TList
{
typedef typename Container<Item>::type type;
};
Then you can define different container policies:
template <typename T>
struct vector_container
{
typedef std::vector<T> type;
};
template <typename T>
struct map_container
{
typedef std::map<T, std::string> type;
};
TList<int, vector_container> v;
TList<int, map_container> m;
A bit verbose, though.* To do things directly, you'd need to take the route described by James, but as he notes this is ultimately very inflexible.
However, with C++0x we can do this just fine:
#include <map>
#include <vector>
template <typename Item,
template <typename...> class Container, typename... Args>
struct TList
{
// Args lets the user specify additional explicit template arguments
Container<Item, Args...> storage;
};
int main()
{
TList<int, std::vector> v;
TList<int, std::map, float> m;
}
Perfect. Unfortunately there's no way to reproduce this in C++03, except via the indirection policy classes introduce as described above.
*I want to emphasize that by "A bit verbose" I mean "this is unorthodox". The correct solution for your problem is what the standard library does, as Jerry explains. You just let the user of your container adapter specify the entire container type directly:
template <typename Item, typename Container = std::vector<Item>>
struct TList
{};
But this leaves a big problem: what if I don't want the value type of the container to be Item but something_else<Item>? In other words, how can I change the value type of an existing container to something else? In your case you don't, so read no further, but in the case we do, we want to rebind a container.
Unfortunately for us, the containers don't have this functionality, though allocators do:
template <typename T>
struct allocator
{
template <typename U>
struct rebind
{
typedef allocator<U> type;
};
// ...
};
This allows us to get an allocator<U> given an allocator<T>. How can we do the same for containers without this intrusive utility? In C++0x, it's easy:
template <typename T, typename Container>
struct rebind; // not defined
template <typename T, typename Container, typename... Args>
struct rebind<T, Container<Args...>>
{
// assumes the rest are filled with defaults**
typedef Container<T> type;
};
Given std::vector<int>, we can perform rebind<float, std::vector<int>>::type, for example. Unlike the previous C++0x solution, this one can be emulated in C++03 with macros and iteration..
**Note this mechanism can be made much more powerful, like specifying which arguments to keep, which to rebind, which to rebind themselves before using as arguments, etc., but that's left as an exercise for the reader. :)
I'm a bit puzzled why some very smart (and competent) people are saying no.
Unless I've misread your question, what you're trying to accomplish is virtually identical to the "container adapters" in the standard library. Each provides an interface to some underlying container type, with the container type that will be used provided as a template parameter (with a default value).
For example, a std::stack uses some other container (e.g., std::deque, std::list or std::vector) to hold the objects, and std::stack itself just provides a simplified/restricted interface for when you just want to use stack operations. The underlying container that will be used by the std::stack is provided as a template parameter. Here's how the code looks in the standard:
namespace std {
template <class T, class Container = deque<T> >
class stack {
public:
typedef typename Container::value_type value_type;
typedef typename Container::size_type size_type;
typedef Container container_type;
protected:
Container c;
public:
explicit stack(const Container& = Container());
bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
value_type& top() { return c.back(); }
const value_type& top() const { return c.back(); }
void push(const value_type& x) { c.push_back(x); }
void pop() { c.pop_back(); }
};
}
Of course, perhaps I've just misunderstood the question -- if so, I apologize in advance to the people with whom I'm (sort of) disagreeing.
Yes and no.
You can use a template template parameter, e.g.,
template <typename Item, template <typename> class Container>
struct TList { /* ... */ };
However, in general, template template parameters are not particularly useful because the number and types of the template parameters have to match. So, the above would not match std::vector because it actually has two template parameters: one for the value type and one for the allocator. A template template parameter can't take advantage of any default template arguments.
To be able to use the std::vector template as an argument, TList would have to be declared as:
template <typename Item, template <typename, typename> class Container>
struct TList { /* ... */ };
However, with this template, you wouldn't be able to use the std::map template as an argument because it has four template parameters: the key and value types, the allocator type, and the comparator type.
Usually it is much easier to avoid template template parameters because of this inflexibility.
well, you can hack it up with a macro:
template <typename T, typename stl_container = std::vector<T> >
struct TList
{
typedef stl_container Type;
};
#define TLIST(T, C) TList<T, C<T> >
TList<int> foo;
TList<int, std::list<int> > bar;
TLIST(int, std::list) baz;
Is it possible to templatize std::vector and create a general container, something like that?
No. You would have to templatize the function or object using the container -- you couldn't templatize the container itself.
For example. consider a typical std::find:
template<class InputIterator, class T>
InputIterator find ( InputIterator first, InputIterator last, const T& value )
{
for ( ;first!=last; first++) if ( *first==value ) break;
return first;
}
This works for any container, but doesn't need a tempalte with the container at all.
Also, given that it looks what you're trying to do is make container independent code, you might want to buy or borrow yourself a copy of Scott Meyers' Effective STL and read Item 2: Beware the illusion of container-independent code.
You can use template template parameters as others have mentioned here. The main difficulty with this is not that dissimilar container types have dissimilar template parameters, but that the standard allows the standard containers, like vector, to have template parameters in addition to the documented, necessary ones.
You can get around this by providing your own subclass types that accept the appropriate template parameters and let any extras (which have to have defaults) be filled in my the implementation:
template < typename T > struct simple_vector : std::vector<T> {};
Or you can use the templated typedef idiom:
template < typename T > struct retrieve_vector { typedef std::vector<T> type; };

Typedef (alias) of an generic class

is it possible in C++ to create an alias of template class (without specifying parameters)?
typedef std::map myOwnMap;
doesn't work.
And if not, is there any good reason?
In C++98 and C++03 typedef may only be used on a complete type:
typedef std::map<int,int> IntToIntMap;
With C++0x there is a new shiny syntax to replace typedef:
using IntToIntMap = std::map<int,int>;
which also supports template aliasing:
template <
typename Key,
typename Value,
typename Comparator = std::less<Key>,
typename Allocator = std::allocator< std::pair<Key,Value> >
>
using myOwnMap = std::map<Key,Value,Comparator,Allocator>;
Here you go :)
Template typedefs are not supported in the C++03 standard. There are workarounds, however:
template<typename T>
struct MyOwnMap {
typedef std::map<std::string, T> Type;
};
MyOwnMap<int>::Type map;
This feature will be introduced in C++0x, called template alias. It will be looking like this:
template<typename Key, typename Value>
using MyMap = std::map<Key, Value>
For C++ lower 11 only one way
template <...>
struct my_type : real_type<...> {}
An alternative approach:
template <
typename Key,
typename Value,
typename Comparator = std::less<Key>
>
class Map: public std::map<Key,Value, Comparator> {
};

Mapping between two sets of classes

I have a requirement where in i have a set of classes and they have a one on one correspondence with another set of classes. Consider something like this
a)
template < class A >
class Walkers
{
int walk( Context< A >* context );
};
The set of Context classes are not templates. They are individual classes. I need to create a mapping between these two sets. One way, i could think of is to create a typelist and refer to the class at the appropriate location. But i feel that is more error prone, as i may mismatch the Contexts in the typelist. Can someone advise me how to do this ?
Thanks,
Gokul.
I am not sure to understand what you want to do, what your requirements or goal are, but you could try to use traits to define the relationship:
// direct mapping
template <typename T>
struct context_of;
template <>
struct context_of<A> {
typedef ContextA type;
};
// reverse mapping
template <typename T>
struct from_context;
template <>
struct from_context< ContextA > {
typedef A type;
};
The code you posted would be written as:
template <typename T>
class Walker {
public:
typedef typename context_of<T>::type context_type;
int walker( context_type* context );
};
To reduce typing you could build the mappings out of typelists (possibly complex), or you might want to use a helper macro (dirtier, simpler):
#define GENERATE_CONTEXT_ENTRY( the_class, the_context ) \
template <> struct context_of< the_class > { \
typedef the_context type; }; \
template <> struct from_context< the_context > \
typedef the_class type; };
GENERATE_CONTEXT_ENTRY( A, ContextA );
GENERATE_CONTEXT_ENTRY( B, ContextB );
#undef GENERATE_CONTEXT_ENTRY
Can you make the Context classes templates and use template specialization for implementing them?
Using boost::mpl:
using boost::mpl;
typedef map< pair< A, ContextA >,
pair< B, ContextB > > context_type_map;
template <typename T>
class Walker {
public:
typedef at< context_type_map, T >::type context_type;
int walker( context_type* context );
};
In fact, I believe that you can use pretty much any type container (boost::mpl::vector) to store pairs and use boost::mpl::find_if with a predicate that extracts the first element of the pair and compares.