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.
Related
I need to get 2 type-parameters for my class: T1, which is a class that has a template, and T2, which is the parameter for T1's template.
In my case, a Vertex type (there are 2, one inherits from the other), and the data type the vertex stores (name/id in my case).
I want to be able to write something like this:
template < typename VertexType < typename VertexIDType > >
(which gave me the error: C2143 syntax error: missing ',' before '<')
So that my class would be something like this:
class Graph
{
public:
Graph(const List<VertexType<VertexIDType>>& verticesList);
VertexType<VertexIDType>& getVertexByID(const VertexIDType& ID) const;
private:
List<VertexType<VertexIDType>> vertices;
};
('List' is my (not std's) implementation for a linked list.)
I also tried template <typename VertexType, typename VertexIDType>
but then I got error in the function Graph(const List<VertexType<VertexIDType>>& verticesList);
(C2947 expecting '>' to terminate template-argument-list, found '<')
and this template < typename VertexType < template <typename VertexIDType> > >
(which also gave me error C2143)
I'm really the kind of person that tries to figure everything by himself, but this is getting frustrating. I couldn't find an answer that I understood if/how to implement in my code.
I've now finished an OOP (c++) course. I have some experience with templates. I've wrote templates that get 1 or 2 arguments successfully, but nothing like this.
Please help me solve this problem, preferably as elegantly as possible :)
Thanks.
You can use template template parameters:
template <template <typename> class VertexType, typename VertexIDType>
class graph;
graph<MyVertexType, MyVertexIDType> //usage
Alternatively you could take just a type and extract the ID type in a partial specialization:
template <typename Vertex>
class graph;
template <template <typename> class VertexType, typename VertexIDType>
class graph <VertexType<VertexIDType>> {
//...
};
graph<MyVertexType<MyVertexIDType>> //usage
TartanLlama's answer is a good one for the question that you asked, but you might want to change your approach slightly. If you require that a VertexType must define a typedef VertexIDType, then you can write:
template <class VertexType>
class Graph
{
public:
Graph(const List<VertexType>& verticesList);
typedef typename VertexType::VertexIDType VertexIDType;
VertexType& getVertexByID(const VertexIDType& ID) const;
private:
List<VertexType> vertices;
};
Note the typename in the typedef for VertexIDType. It is needed to say "this name must be a type and not a variable".
Assuming your current VertexType is templated on VertexIDType:
template <classname VertexIDType>
struct VType1 {
double stuff; // Or whatever you have in your vertex
};
You would need to change it to:
template <classname VertexIDType>
struct VType1 {
double stuff;
typedef VertexIDType VertexIDType; // Provide a typedef for VertexIDType.
};
This is similar to the approach the standard library takes, where every type which is a container has a typedef for value_type etc.
I have a data container which has following requirements:
Be fast: Hence templates and not normal inheritance
Use different implementations
Be able to extend those implementations with more methods
Data is specified via template argument and needs to be able to save pointers to data container items
The solution I have come up with is as follows:
template<typename T, template<typename> class container_t>
class data_c
{
public:
typedef data_c<T, container_t> value_type;
typedef typename container_t<value_type>::ref container_ref;
container_ref link;
T c;
};
template<typename T>
class storage_container_impl
{
public:
typedef T value_type;
typedef storage_container_impl<T>* ref;
T data;
};
template<typename _impl>
class storage_container : public _impl
{
public:
typedef typename _impl::value_type value_type;
typedef typename _impl::ref ref;
};
template<typename T>
using impl_storage_container = storage_container<storage_container_impl<T> >;
typedef impl_storage_container<data_c<int, impl_storage_container> > c_storage_container;
int main()
{
c_storage_container tmp;
tmp.data.c=5;
tmp.data.link=&tmp;
return tmp.data.c;
}
Which results in following error (gcc 4.7):
test1.cpp:6:48: error: no type named 'ref' in 'impl_storage_container<data_c<int, impl_storage_container> > {aka class storage_container<storage_container_impl<data_c<int, impl_storage_container> > >}'
It works if I use T *data instead of T data (But I do not want that indirection), or if I do not use storage_container_impl and have T data directly in storage_container. Using storage_container_impl mixin-style does not solve the problem as well. As container_ref is a pointer, there also should be no reason why it does not work, e.g. because there is a loop in the template declaration. This is a minimized version of the problem. Any help would be appreciated!
I know that it's not a perfect solution, but you can try to replace
typedef impl_storage_container<data_c<int, impl_storage_container> > c_storage_container;
with
typedef impl_storage_container<data_c<int, storage_container_impl> > c_storage_container;
It compiles and work. Otherwise you get endless type recursion.
If I have the following template parameters:
template <typename T_Key, typename T_Value, typename T_HashFunc,
typename T_ExtractKey, typename T_EqualKey, typename T_RehashClass, typename T_HashcodeClass>
class Hashtable { /* ... */ };
Where T_RehashClass and T_HashcodeClass are two template classes that take in T_Key, T_Value, T_HashFunc, T_ExtractKey and T_EqualKey as well. I would like those classes to grab the types from Hashtable's typedef list (all template parameter types in Hashtable are typedefined).
Note that T_RehashClass and T_HashcodeClass can be created by the user as well (defaults are provided) and can have other template parameters if the user wishes.
As it stands, any class that is a T_RehashClass must have T_Key, T_Value etc. template parameters filled out, which I see as code duplication. I would like the class to somehow have knowledge of Hashtable so that it can access its typedefs and deduce T_Key, T_Value etc. types automatically by creating its own typedefs. Unfortunately, in this case, I get a cyclic dependency.
How is this type of problem solved generally?
Also note that I am following EASTL where EASTL uses multiple inheritance to inherit from T_RehashClass and T_HashnodeClass instead and consequently, Hashtable has even more template parameters. I wondered if there was a way around it (i.e. not inheriting from both policies and have them as template parameters as inheriting from the policies reduces flexibility).
One solution that I thought of was to have a template struct that has all the template parameters from T_Key to T_EqualKey. The Hashtable declaration will then be:
template <typename T_HashtableParams, typename T_RehashClass = default_rehash_class<T_HashtableParams>, typename T_HashcodeClass = default_hashnode_class<T_HashtableParams> >
class Hashtable { /* ... */ };
The T_RehashClass and T_HashcodeClass can then take the defaults which will eliminate code duplication. Problem with this approach is that it is more cumbersome for the user to use.
I'm not sure it's terribly interesting to specify different T_Key and T_Value types for your hash and rehash classes. If I were going about this problem, I would try and set up a policy for the key/val first. My inclination is to say that there maybe should be a ValuePolicy instead of grouping it with KeyPolicy, but that is neither here nor there.
namespace hash {
namespace detail {
template<
typename Key
, typename Value
, typename KeyGetter
, typename KeyComparator>
class KeyPolicy {
public:
typedef Key key_t;
typedef Value value_t;
typedef KeyGetter get_t;
typedef KeyComparator compare_t;
};
}} // hash detail
The HashTable isn't valid unless it has the same KeyPolicy as the rehast, etc so don't give it one.
namespace hash {
namespace detail {
template<typename RehashPolicy>
class HashTableImpl {
public:
typedef RehashPolicy rehash_p;
typedef typename rehash_p::key_policy_t::key_t key_t;
// typedef ...
};
// this doesn't have a specific name, its anything.
template<typename KeyPolicy>
class SomeRehashPolicy {
public:
typedef KeyPolicy key_policy_t;
};
}} // hash detail
You can add whatever typedefs you want there, obviously. If I were a stickler in a code review I'd probably ask for things like rehash_p and key_policy_t to be private. They are implementation details, really. The actual invariant you are trying to protect are what are in key_t, etc.
Maybe I'm outside the reasonable bounds of etiquette, but my honest opinion is that all this configuration is only interesting to the guy that wrote it. Not you, not anyone using it. So I would only expose the HashTable configuration or two that people are actually going to use.
namespace hash {
struct stub {}; // sorry, I'm lazy
template<typename Key, typename Value>
class HashTable {
private:
typedef typename detail::KeyPolicy<Key, Value, stub, stub> key_p;
typedef typename detail::SomeRehashPolicy<key_p> rehash_p;
typedef typename detail::HashTableImpl<rehash_p> impl_t;
public:
typedef typename impl_t::key_t key_t;
};
} // hash
int main(int argc, char ** argv) {
hash::HashTable<int, double> hash_table;
return 0;
}
Lots of details aren't filled in obviously, but you get the idea.
See e.g. Modern C++ Design (sec. 1.5.1: Implementing Policies with template-template parameters). The idea is to let T_RehashClass and T_HashcodeClass be template-template parameters. These classes take the T_Key, T_Value and whatever else as their own parameters. To avoid retyping, you can then inherit the needed instantiation of those templates.
template <
typename T_Key,
typename T_Value,
typename T_HashFunc,
typename T_ExtractKey,
typename T_EqualKey,
template<typename, typename /*, more params */> class T_RehashClass,
template<typename, typename /*, more params */> class T_HashcodeClass
> class Hashtable
:
public T_RehashClass<T_Key, T_Value /*, more params */>,
public T_HashcodeClass<T_Key, T_Value /*, more params */>
{ /* ... */ };
NOTE: you really need "class" and not "typename" in front of T_RehashClass and T_HashcodeClass because they are template names, not template types!
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.
I have a set of classes in a logging framework used by project A and B. I am refactoring the framework so it can be used in project B and C. The refactoring mainly consists of giving everything template parameters: project A might run on an embedded device with poor/no STL implemenatation, while B and C just run on a pc, but B is single threaded while C uses multithreading.
This works well, but results in what seems to me an awfull lot of template parameters and a rather ugly typedef mess. I need like 20 lines to typedef all classes I'm going to use, and there are also lots of classes taking a template parameter they do not use themselves, but is needed to be able to typedef another class they do use (which is not per se a bad thing, but in the end everything starts to llok really complicated). Another problem is that when I want to add some functionality to class A and it requires adding a container, class A needs an extra template paramater. As a result, all other classes seeing/using class A suddenly also need that extra parameter leading to a domino effect.
Slightly exaggerated example:
template< class string, class map, class mutex >
class MessageDestination
{
typedef Message< string, map > message_type;
virtual void Eat( const message_type& ) = 0;
}
template< class string, class map, class stream >
class MessageFormatter
{
typedef Message< string, map > message_type;
virtual void Format( const message_type&, stream& ) = 0;
}
template< class string, class map, class containerA,
template< class, class > containerB, template< class, class > class queue, class allocator >
class ThreadedMessageAcceptor
{
typedef Message< string, map > message_type;
typedef MessageDestination< string, map > destination_type;
typedef containerB< destination_type, allocator > destinations_type;
typedef queue< message_type, allocator > messages_type;
};
I can think of some techniques to clean this up, but I'm having a hard time deciding what one or which combination to use. StackOverFlow, your help will be appreciated!
Here's the first solution I thought of, joining parameters together into the type they'll eventually form:
template< class message, class mutex >
class MessageDestination
{
virtual void Eat( const message& ) = 0;
}
This makes it simpler, but doesn't it at the same time it kind of hides what message actually is? Suppose a user wants to provide an implementation, he does not directly see that message has to use a certain string type etc.
Another technique I thougt about, but cannot recall having seen before somwhere which makes it look suspicious, is simply defining everything in a single struct and passing that as single template parameter to everything:
struct MyTemplateParameters
{
typedef std::string string;
typedef std::map map;
typedef std::queue queue;
typedef LightMutex mutex;
template< class A, class B >
struct DefineContainerB
{
typedef containerB< A, B >::type;
}
//....
};
template< class parameters >
class MessageDestination
{
typedef Message< parameters > message_type;
virtual void Eat( const message_type& ) = 0;
};
template< class parameters >
class ThreadedMessageAcceptor
{
typedef Message< parameters > message_type;
typedef MessageDestination< parameters > destination_type;
typedef parameters::DefineContainerB< destination_type, parameters::allocator >::type destinations_type;
};
This is nice as it allows specifying everything at one single point, and the typedefs to all classes will all be class XXX< MyTemplateParameters >, but again, it gives me an uneasy feeling. Is there a reason for this?
The “other” technique is very common in C++. The parameters class is usually called a “trait class”.
This is the way to go (why does it give you an uneasy feeling?). It is used pervasively in the Boost libraries and other C++ libraries. Even the standard library uses it, e.g. in the std::basic_string class.
An equally well-established alternative are metafunctions. At its most basic, a metafunction is a “function” that operates on types rather than objects. So where a function takes value arguments and returns a value, a metafunctions takes template arguments and “returns” a type:
template <typename T>
struct identity {
typedef T type;
};
The metafunction is used (“invoked”) like a normal type definition.
typedef identity<int>::type mytype; // or
identity<int>::type x;
Not very useful in this case. But consider the following common metafunction:
template <typename T>
struct remove_const {
typedef T type;
};
template <typename T>
struct remove_const<T const> {
typedef T type;
};
This can be used to make an arbitrary type (in particular a template argument) non-const. This is actually a type I’m currently using in a project: I have a class that accepts both const and non-const types and offers appropriate interfaces. However, internally I need to store a non-const reference. Simple, I just use the following code in my class:
typename remove_const<T>::type& _reference;
(The typename is required because T is a template argument and that makes remove_const<T>::type a dependent type. Your above example code is actually omitting quite a few required typenames – it won’t compile on several modern compilers!)
Now, how to apply this to your problem?
Create two empty marker types that specify whether your types are used on an embedded device or on a compliant compiler:
struct Embedded { };
struct Compliant { };
Now you can define your classes in terms of these, e.g.:
template<typename Spec>
class ThreadedMessageAcceptor
{
typedef Message< Spec > message_type;
typedef MessageDestination< Spec > destination_type;
typedef typename Allocator< destination_type, Spec >::type allocator_type;
typedef typename ContainerB< destination_type, allocator_type, Spec >::type destinations_type;
};
Here, Spec will be either Compliant or Embedded. So to use it on a standards compliant compiler, write:
ThreadedMessageAcceptor<Compliant> x;
The class uses the following metafunctions:
template <typename T, typename Spec>
struct Allocator { };
template <typename T, typename Alloc, typename Spec>
struct ContainerB { };
You need to remember to specialize them appropriately for your target specifications, e.g.:
template <typename T>
struct Allocator<T, Compliant> {
typedef std::allocator<T> type;
};
template <typename T, typename Alloc>
struct ContainerB<T, Alloc, Compliant> {
typedef std::vector<T, Alloc> type;
};
This already shows that a metafunction may have arbitrarily many arguments besides the Spec (which I’ve put last on a whim – but its placement should be consistent).
To be sure, this is more code than when using a single trait class but it has lower cohesion, logically separates concerns and is easier to reuse.