A C++ hash_map has the following template parameters:
template<typename Key, typename T, typename HashCompare, typename Allocator>
How can I specify a Allocator without specifying the HashCompare?
This won't compile :(
hash_map<EntityId, Entity*, , tbb::scalable_allocator>
The simple answer is that you can't. You cannot skip a template parameter and have it choose the default value for the template. Your only option is to find out what the default is and insert it into your declaration.
There's one trick you can use which will at least save you having to work out what the default is, but it does require that you know the name of the type as it is defined in hash_map.
The hash_map will probably be declared something like:
class allocator {};
class hash_compare {};
template<typename Key
, typename T
, typename HashCompare = hash_compare
, typename Allocator = allocator>
class hash_map
{
public:
typedef HashCompare key_compare;
// ...
};
We cannot leave out the default for the hash, but we can refer to the default using the member typedef:
hash_map<EntityId
, Entity*
, hash_map<EntityId,Entity*>::key_compare // find out the default hasher
, tbb::scalable_allocator> hm;
If you're going to use the type a lot, then create a typedef:
typedef hash_map<EntityId,Entity*>::key_compare EntityKeyCompare;
hash_map<EntityId
, Entity*
, EntityKeyCompare
, tbb::scalable_allocator> hm;
If the has map type has some public typedef for the HashCompare template parameter, you could write a meta function that uses a vanilla hash map type to get the std comparator. Something like this:
template< typename Key, typename T, typename Allocator>
struct hash_map_type {
typedef typename hash_map<Key,T>::key_compare key_compare;
typedef mash_map<Key,T,key_compare,Allocator> result_t;
};
typedef hash_map_type<int,string,my_allocator>::result_type my_hash_map;
This, however, depends on something like the above hash_map<Key,T>::key_compare being accessible.
Related
I was reading this tutorial on variadic templates, but in below code:
template<int index, class C>
struct container_index {
// points to the "next" container type
typedef typename container_index<
index-1,
typename C::base_container
>::container_type container_type;
// points to the next T-type
typedef typename container_index<
index-1,
typename C::base_container
>::type type;
};
these typedefs seems redundant but it compiles well. The problem is simply I dont understand why they are like this and I didnt find a tutorial explaining this case. Could someone give some explanation? Why the typedef name is repeated:
"::container_type container_type;"
"::type type;"
It couldn't be just like that:
typedef typename container_index<
index-1,
typename C::base_container
> type;
Many thanks.
The example demonstrates a recursive type definition in templates. The key is that the recursion base case is specified as a specialisation for index=0:
template<class C>
struct container_index<0, C> {
// point to C instead of C::base_container
typedef C container_type;
// point to C::type instead of C::base_container::type
typedef typename C::type type;
};
It is this base-case that makes the type deduction possible. So for example, the type container_index<2, MyCont>::container_type is expanded to container_index<1, MyCont>::container_type, which in turn expands to container_index<0, MyCont>::container_type, which finally expands to MyCont.
typedef gives a type a name. So you need to supply both the type and the name you want to give it.
In
typedef typename container_index<index-1, typename C::base_container>::type type;
the typename container_index<index-1, typename C::base_container>::type is us describing the type we want to give a name to, and that final type before the semicolon is the name we want to call it.
Compare:
struct Example
{
typedef Fruit::orange citrus; // declare a type called Example::citrus, which is the same type as Fruit::orange
typedef Fruit::apple apple; // declare a type called Example::apple, which is the same type as Fruit::apple - the same operation as the line above, and so the same syntax!
};
Please don't get my "late binding" wrong, I don't mean usual late binding at runtime, I mean something else and cannot find a better word for it:
Consider I am working on a container (or similar) data structure Containor for some value type V that needs to compare these values with a comparator, so my first template looks like this
template<typename Val, typename Comp = std::less<Val>>
struct Containor{};
Now, my Containor structure makes use of another container internally. Which container is to be used should be configurable by template arguments as well, lets say the default is std::set. So my next version of Containor looks like this:
template<typename Val, typename Comp = std::less<Val>, typename Cont = std::set<Val,Comp>>
struct Containor{};
and here is where the code begins smelling IMHO. As long as the user is satisfied with the default implementation of the inner container, everything is fine. However, suppose he wants to use the new google btree set implementation btree::btree_set instead of std::set. Then he has to instanciate the template like this:
typedef Containor<int,std::less<int>,btree::btree_set<int,std::less<int>> MyContainor;
^^^^^^^^^^^^^^^^^^^
I have underlined the part where my problem lies. The CLIENT CODE has to instanciate the btree_set with the right parameters. This honestly sucks, because the Containor class always needs a set of exactly the same type and comparator as its own first two template arguments. The client can - by accident - insert other types here! In addition, the client has the burden of choosing the right parameters. This might be easy in this case, but it hard if the inner container must for example be a set of pairs of the value type and some other type. Then the client has an even harder time getting the type parameters of the inner set correct.
So what I want is a way in which the client code only hands in the raw template and the Containor internally instanciates it with the correct arguments, i.e. something like that:
template<typename Val, typename Comp = std::less<Val>, typename Cont = std::set >
struct Containor{
typedef Cont<Val,Comp> innerSet;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ container instanciates the inner containor
};
typedef Containor<int,std::less<int>,btree::btree_set> MyContainor;
// ^^^^^^^^^^^^^^^^
// client only hands in raw template
Of course, this is no valid C++!
So I thought about ways to solve this problem. The only solution I could think of was writing "binder classes" for all data structures I want to use, like this:
struct btree_set_binder{
template<typename V, typename C = std::less<V>>
struct bind{
typedef btree::btree_set<V,C> type;
}
};
Now I can define my Containor with a set binder
template<typename Val, typename Comp = std::less<Val>, typename ContBinder = btree_set_binder >
struct Containor{
typedef btree_set_binder::bind<Val,Comp>::type innerSet;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ works like a charm
};
Now, the user must only supply the desired binder class and the Containor will instanciate it with the right arguments. So these binder classes would be okay for me, but it is quite a hassle writing binder classes for all containers. So is there a better or easier way to bind template arguments "late" in C++11, i.e., inside another template that retrieves the raw template as parameter.
Maybe make your own comparator trait.
// Comparator trait primary template
template <typename T> stuct MyComparator
{
typedef typename T::key_compare type;
};
// Comparator trait non-standard usage example
template <typename U, typename V, int N>
struct MyComparator<WeirdContainer<U, V, N>>
{
typedef std::greater<V> type;
};
template <typename T, typename Cont = std::set<T>>
struct MyAdaptor
{
typedef typename MyComparator<Cont>::type comparator_type;
typedef T value_type;
// ...
};
I've renamed your "Containor" to "MyAdaptor", since this sort of construction is usually called an "adaptor" class.
Usage:
MyAdaptor<int> a; // uses std::set<int> and std::less<int>
MyAdaptor<double, WeirdContainer<bool, double, 27>> b;
Update: In light of the discussion, you could even remove the outer type argument entirely:
template <typename Cont> struct MyBetterAdaptor
{
typedef MyAdaptorTraits<Cont>::value_type value_type;
typedef MyAdaptorTraits<Cont>::pred_type pred_type;
// ...
};
To be used like this:
MyBetterAdaptor<std::set<int>> c; // value type "int", predicate "std::less<int>"
Writing the MyAdaptorTraits template is left as an exercise.
So what I want is a way in which the client code only hands in the raw
template and the Containor internally instanciates it with the correct
arguments,
So what you need is obviously a template template parameter:
// std::set has three template parameters,
// we only want to expose two of them ...
template <typename V, typename C>
using set_with_defalloc = std::set<V,C>;
template<
typename Val,
typename Comp = std::less<Val>,
template <typename V, typename C> class Cont = set_with_defalloc>
struct Containor{
typedef Cont<Val,Comp> innerSet;
// ...
};
You should be able to do it with template template parameters, as in:
template<typename Val, typename Comp = std::less<Val>, template <typename...> class ContBinder = std::set>
struct Containor {
typedef ContBinder<Val, Comp> innerSet;
// ...
};
Note: you need the variadic typename... because std::set takes three template parameters (the third being an allocator) while other containers might not.
I'm currently facing a problem I haven't been able to solve myself.
Basically what I'm trying to do is implement some linq-like behaviour in C++.
I'll start off with the code in my header:
template<typename T, template<class = T> class A,
template<class = T, template<class=T> class = A> class C>
class queryable
{
public:
typedef T value_type;
typedef A<value_type> allocator_type;
typedef C<value_type, allocator_type> container_type; // (1)
typedef queryable<T, A, C> type;
queryable(container_type const &) { }
template<typename _Out> queryable<_Out, A, C> select(/* some delegate */);
// more methods etc
}
And this is how I'd like it to be instantiated:
std::vector<int> my_vec;
queryable<std::vector<int> > q(my_vec);
Needless to say this doesn't work (otherwist I wouldn't be here :) )
Now the even stranger part is that even this doesn't seem to work:
std::vector<int> my_vec;
queryable<int, std::allocator, std::vector> q(my_vec);
As you can see (by looking at the select function), it is important to me to not just use something like this:
template<typename T> class queryable;
Any suggestions on how to solve this? And is this even possible?
Any help would be appreciated!
EDIT: the errors I'm getting:
../entry.cpp:19:58: error: type/value mismatch at argument 3 in template parameter list for ‘template<class T, template<class> class A, template<class, template<class> class<template-parameter-2-2> > class C> class failproof::collections::queryable’
../entry.cpp:19:58: error: expected a template of type ‘template<class, template<class> class<template-parameter-2-2> > class C’, got ‘template<class _Tp, class _Alloc> class std::vector’
../entry.cpp:19:61: error: invalid type in declaration before ‘;’ token
EDIT 2:
As far as I understand the compiler is complaining about C not taking 2 class arguments, but 1 class argument and 1 templated class argument (1), because I defined C to be that way.
Is there any way to resolve this issue?
There is a general method to 'explode' a type to test if it was created by a template, and to extract the types that were passed to that template. It is also possible to access the template itself and pass other parameters to it if you desire.
vector is a class template. When you apply parameters to it, you get something like vector<int>, which is a template class. A template class is a specific type, like any other type, it just happens to have been created via a class template.
The goal is, given a type T, to test if it is a template class, and if so to gain access to the class template that was used to create it, and also to access the parameters that were passed to the class template. In this sample, I just test for whether something is a one-arg or two-arg template, but the technique can easily be extended.
(Technically, vector is a two-arg template. There is a default for the second parameter, so vector<int> is actually vector<int, allocator<int> >, but it's still basically a two-arg template, not a one-arg template.)
The best place to start is with this sample code I've put on ideone. I'll copy the Exploder code at the end of this answer.
I begin with
typedef list<int> list_of_ints;
and proceed to use the Exploder template to access all the above information. For example, Exploder<list_of_ints> :: type_1 is the first parameter that was passed to the template, in this case int. The second parameter (this is the defaulted parameter) is allocator<int> and is accessible with Exploder<list_of_ints> :: type_2.
typedef Exploder<list_of_ints> :: type_2 should_be_an_allocator_int;
Given this second type, which we know was created by a template, we can access its parameter type, int, with Exploder< should_be_an_allocator_int > :: type_1, but it's more interesting to actually access the allocator template instead and pass a different parameter to it. This next line evaluates, in this example, to an allocator<double>.
typedef Exploder< should_be_an_allocator_int >
:: rebind<double> :: type should_be_an_allocator_double;
So, even if your list<...,...> type did not use the default allocator, you can access the allocator that was used, and also any class template that was used to create the allocator type.
Now that we have a suitable allocator, we can go back to our original template class list<int> and replace int with double:
Exploder<list_of_ints> :: rebind<double, should_be_an_allocator_double> :: type
To verify all this has worked, the sample code uses typeid(...).name() to print the actual type of the various objects, along with the correct type that it should be. You can see that they match.
(Also, some templates are such that their parameters are not types, but other class templates, or even other template templates. It should be possible to extract all that, but I'm not going to look into that here.)
(One last interesting technical note. Some types, such as allocator, have something called rebind to allow this sort of access. But the technique used above works for all template classes, even those without their own rebind)
The full code for the template Exploder
See sample code I've put on ideone for a full demo.
template <class>
struct Exploder;
template<class T, template<class> class Template>
struct Exploder< Template<T> > {
static const char * description() { return " One-arg template. Arg 1 is a type "; }
typedef T type_1;
template <class V>
struct rebind {
typedef Template<V> type;
};
};
template<class T, class U, template<class,class> class Template>
struct Exploder< Template<T,U> > {
static const char * description() { return " Two-arg template. All args are types, as opposed to being (unapplied) templates. "; }
typedef T type_1;
typedef U type_2;
template <class V,class W>
struct rebind {
typedef Template<V,W> type;
};
};
template<class S, class T, class U, template<class,class,class> class Template>
struct Exploder< Template<S,T,U> > {
static const char * description() { return " Three-arg template. All args are types, as opposed to being (unapplied) templates. "; }
typedef S type_1;
typedef T type_2;
typedef U type_3;
};
The second template parameter of the standard containers (the allocator) is a type, not a template, so you need to change your third parameter to something like
template<typename, typename> class C
(Note that the default arguments in your template parameter specifications don't serve any purpose, so I omitted them here.)
Then you should be able to instantiate the template as
queryable<int, std::allocator, std::vector>
You may be better off just parametrising over the container type, and then using its value_type and allocator_type definitions:
template <typename C> class queryable
{
public:
typedef typename C::value_type value_type;
typedef typename C::allocator_type allocator_type;
typedef C container_type;
};
(One downside is that you can't directly access the allocator template; however, you can use the allocator type's nested rebind definition if you need to instantiate that template for other types.)
Also, typedef iterator const const_iterator; is wrong; that declares an unmodifiable iterator that can be used to modify the sequence, while const_iterator is supposed to be a modifiable iterator that can't be used to modify the sequence.
(A note on terminology. vector is a class template, i.e. without any parameters. And vector<int> is a template class, i.e. a class almost like any other except that it was created by a template.)
It is possible to use it as you wish, where queryable takes one template parameter:
queryable< vector<int> > q;
This means that querable is a template with just one parameter:
template <typename T>
struct queryable;
You then use a specialization that has more than one parameter:
template <typename ValueType, template<class T,class = allocator<T> > class ContainerTemplate>
struct queryable< ContainerTemplate<Contained> > {
typedef ValueType value_type;
typedef ContainerTemplate<ValueType> container_type;
typedef typename container_type :: allocator_type A;
// typedef ContainerTemplate <WhateverOtherValueTypeYouWish> ...
// typedef A :: rebind <SomeOtherType> ...
};
The last two lines, commented out, show how you can use ContainerTemplate as a class template, creating other types as required. ContainerTemplate is vector or list or set or something like that.
As #MikeSeymour has pointed out, the use of rebind might be the way to access the allocator class template.
Sample code on ideone
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!
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> {
};