Normally in templates you want to know the entire type, but in my case I need to know more, and want to "break up" the type. Take this example:
template <typename Collection<typename T> >
T get_front(Collection const& c)
{
return c.front();
}
How can I achieve that? Note: I need it to to automatically deduce the types, not pass in something like <std::vector<int>, int>
Edit: A C++0x way can be found at the end.
Edit 2: I'm stupid, and a way shorter C++98/03 way than all this traits stuff can be found at the end of the answer.
If you want your function to work for any arbitary standard library container, you need to pull out some Template Guns.
The thing is, that the different container take a different amount of template parameters. std::vector, std::deque and std::list for example take 2: the underlying item type T and the allocator type Alloc. std::set and std::map on the other hand take 3 and 4 respectively: both have the key type K, map takes another value type V, then both take a comparator Compare type and the allocator type Alloc. You can get an overview of all container types supplied by the standard library for example here.
Now, for the Template Guns. We will be using a partially specialized traits metastruct to get the underlying item type. (I use class instead of typename out of pure preference.)
template<class T>
struct ContainerTraits;
// vector, deque, list and even stack and queue (2 template parameters)
template<
template<class, class> class Container,
class T, class Other
>
struct ContainerTraits< Container<T,Other> >{
typedef T value_type;
};
// for set, multiset, and priority_queue (3 template parameters)
template<
template<class, class, class> class Container,
class T, class Other1, class Other2
>
struct ContainerTraits< Container<T,Other1,Other2> >{
typedef T value_type;
};
// for map and multimap (4 template parameters)
template<
template<class, class, class, class> class Container,
class Key, class T, class Other1, class Other2
>
struct ContainerTraits< Container<Key,T,Other1,Other2> >{
typedef Container<Key,T,Other1,Other2> ContainerT;
// and the map returns pair<const Key,T> from the begin() function
typedef typename ContainerT::value_type value_type;
};
Now that the preparation is done, on to the get_front function!
template<class Container>
typename ContainerTraits<Container>::value_type
get_front(Container const& c){
// begin() is the only shared access function
// to the first element for all standard container (except std::bitset)
return *c.begin();
}
Phew! And that's it! A full example can be seen on Ideone. Of course it would be possible to refine that even further, to the point of returning the actual value that is mapped to a key in a std::map, or use container specific access functions, but I was just a bit too lazy to do that. :P
Edit
A way easier C++0x way is using the new trailing-return-type function syntax, of which an example can be found here on Ideone.
Edit 2
Well, I don't know why, but I totally didn't think of the nested typedefs when writing this answer. I'll let the verbose way stay as a reference for traits classes / pattern matching a template. This is the way to do it, it is basically the same I did with the traits classes, but ultimately less verbose.
You could do this if you know it's not an associative container.
template <typename Collection>
Collection::type_name get_front(Collection const& c)
{
return c.front();
}
I'm assuming you want both Collection and T as template parameters. To do that simply type
template< template < typename > class Collection, typename T >
T get_front( Collection< T > const& c )
...
The construct template < typename > class Collection tells the compiler that Collection is a template itself with one parameter.
Edit:
As pointed out be Xeo, vector takes two template parameters, and your templates need to reflect that, i.e.
template< template < typename, typename > class Collection,
typename T, typename Alloc >
T get_front( Collection< T, Alloc > const& c )
...
Seeing as Collection<T> is known ahead of time, I think what you want is:
template <typename T>
T get_front(Collection<T> const& c)
{
return c.front();
}
The only part that's changing is what T is, it's always in a Collection (contents, not the container) so you don't have put that as part of the template.
If the container was changing, using c.front() could be dangerous. You would need to verify that the collection type had a method front that took no parameters and return a T.
Edit:
If you do need to template Collection, then that's more like:
template<typename C, typename T>
T get_front(C<T> const & c)
I would avoid something that generic if you can, perhaps specializing the function for collections you know will be used, or to a particular class of classes (if possible).
Related
This is somewhat similar to a previous question of mine, I'm trying to implement a templated Map class.
template<typename T, size_t M> class Array { ... } // Fixed-size container
template<typename T> class Vector { ... } // Variable-size container
Method 1:
template<typename KeyContainer, typename ValueContainer> class Map
{
KeyContainer keys;
ValueContainer values;
}
The problem here is I cannot guarantee that both containers will be the same, the user may pass an Array<T, M> as the key container and a Vector<T> as the value container leading to problems once the Map starts to exceed the size specified in the Array<T, M> template.
Method 2:
template<typename KeyType, typename ValueType, template<typename> class Container> class Map
{
Container<KeyType> keys;
Container<ValueType> values;
// What if Container is an Array<T, M>?
}
but as demonstrated in my previous question that I linked it seems it is impossible to do so: receive a container template that has varying parameter count, unless there's some clever template tricks I'm not aware of.
Method 3:
Implement Method 1 and just put a note in the documentation that tells the user that KeyContainer and ValueContainer must be the same type of container.
Question:
What would be the most optimal way to go about this problem?
Method 2 is a good solution, as you users can always "bind" template parameters by using template aliases:
template <typename T>
using ArrayOf5 = Array<T, 5>;
int main()
{
Map<int, float, ArrayOf5> m;
}
live wandbox example
You could allow Container to take more template parameters by using a variadic pack:
template <typename...> class Container
But then it wouldn't work for non-type template parameters as in the case of Array.
You could store data as:
template <class Key, class Value, template<typename> class Container>
class Map
{
Container<std::pair<Key, Value> > store;
};
Disclaimer: Personally I don't think this makes much sense. I don't see a use case for changing the Container used in a Map ever. It is also very hard for any user of your Map to see all requirement for a Container (eg. what methods does a Container need? Which may throw? Which are const?) In any reasonable scenario, users will use some default Container of yours. In any case the additional template argument won't see much use which is why I'd stick to a specific Container type.
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.
in my work we do a lot of pair programming, and i wrote a function that ONLY accepts containers of a SINGLE type or its derivates, but my co-worker is afraid it will fail code review because it looks so damn ugly and says there's gotta be a better way:
here is the signature, the Fruit class is a base class that i renamed Fruit just for this thread:
template <class Container>
typename enable_if<is_base_of<Fruit, typename remove_pointer<typename Container::value_type>::type>::value, void>::type
processFruits(container& fruits)
{
//process the elements and change them if needed. thats why no const
}
what it does is: returns void and enables the function IF its a container AND the type inside the container is a Fruit and/or derivided of fruit. i also used std::remove_pointer because i needed to know the "type" of the pointer (the container will most likely have pointers).
this compiles and works as intended, but as i said i don't know it its the best way to do it, it seems too verbose and might get cut of on code review.
EDIT: this also accepts templated classes, don't have to be containers. is there a way i can limit it to only accept STL containers?
any alternate ideas or is it fine like it is?
thanks in advance.
It is a bit horrible to read.
Well for starters you don't need to say enable_if<B, void> you can just say enable_if<B> and use the default template argument.
You can easily split it into separate pieces:
template <class T>
struct is_fruity
: is_base_of<Fruit, T>
{ };
template <class Container, typename Value = typename Container::value_type>
struct is_fruit_container
: is_fruity<typename remove_pointer<Value>::type>>
{ };
template<class Container>
typename enable_if<is_fruit_container<Container>::value>::type
processFruits(Container& fruits)
{
//process the elements and change them if needed. thats why no const
}
If you have a compiler supporting alias templates you can make it even easier to read:
template<typename Cond>
using Require = typename enable_if<Cond::value>::type;
template<class Container>
Require<is_fruit_container<Container>>
processFruits(Container& fruits)
{
//process the elements and change them if needed. thats why no const
}
this also accepts templated classes, don't have to be containers. is there a way i can limit it to only accept STL containers?
I'm not sure what you mean by "templated classes", it only accepts types with a nested value_type type which is a type derived from Fruit or a pointer to such type, it doesn't have to be a template. To limit it to "STL containers" you need to write a trait to indentify an "STL container", however you want to define that. To do it properly you'd need a trait that tests for begin(), end(), size() members, as well as all the nested types specified by the container requirements, iterator, value_type, etc.
template<typename C, typename Chead, typename... Ctail>
struct static_and
{
static const bool value = C::value && static_and<Chead, Ctail...>::value;
};
template<typename C>
struct static_and<C>
{
static const bool value = C::value;
};
template<typename C>
struct is_container
: static_and<has_begin<C>, has_end<C>, has_iterator<C>, has_value_type<C> /* etc */>
{ };
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
This code does not automatically infer the return type correctly (a design aspect of C++):
template < typename Container,
typename UnaryOp>
Container
mymap(Container c, UnaryOp op)
{
typedef typename Container::value_type ResultType
Container<ResultType> result;
for(Container::iterator i = c.begin();
i != c.end();
i++)
{
result.push_back(op(*i));
}
return result;
}
What I would like to do is have something like this happen:
vector<string> bar;
bar.push_back("1");
bar.push_back("2");
bar.push_back("3");
vector<int> foomatic;
foomatic = mymap(bar, [] (string s)->int {return atoi(s.c_str());});
//foomatic now is equal to {1,2,3}
I was figuring that Container would be inferred to be vector, and ResultType would be inferred to be int.
After the question changed:
You are using the same type, Container, for input and output. But your input and output types are distinct: your input is vector<string>, whereas your output is vector<int>. No wonder that C++ refuses to compile this.
Your problem is now to deduce the return type from the input types. Generally, C++ cannot do that. It’s as simple as that: overload resolution and template resolution only happens based on the input arguments, never on the return type (in some cases elaborate tricks involving proxy objects and implicit casts can be used to work around this but let’s not go there).
The simplest and most idiomatic solution is just to specify the return element type manually when calling the function, as in:
foomatic = mymap<int>(bar, [] (string s)->int {return atoi(s.c_str());});
This requires that the return element type be put first in the template argument list:
template <
typename ResultType,
template<typename> class Container,
typename InputType,
typename UnaryOp>
Container<ResultType> mymap(Container<InputType> c, UnaryOp op) { ... }
However, that does not work because std::vector does not fit the declaration of template<typename> class. Why? Simple reason: because it has more than just one template argument. In particular, the standard says that it has at least one extra template argument to specify the allocator.
Solution: declare the template argument as template<typename, typename> class, right?
No. Now, this does work for some standard library implementations. But besides the mandated two template arguments, the containers may have additional template arguments that take default values (this is often used to pass policy classes to a container, for example; the allocator is already such a policy class).
This is a fundamental problem: we cannot declare Container so that it conforms to all possible type signatures of containers in C++. So this solution, too, is a no-go.
The best solution is unfortunately more complicated, we need to rebind the container type explicitly. This we can do via an extra metafunction:
template <typename C, typename T>
struct rebind;
We need to partially specialize this metafunction for each possible number of template parameters. For example, to make it work with the minimal std::vector, we’d need the following partial specialization:
template <
template <typename, typename> class C,
typename Old,
typename New,
typename A>
struct rebind<C<Old, A>, New> {
typedef typename A::template rebind<New> Rebound;
typedef C<New, typename Rebound::other> type;
};
This looks daunting. What it does is take an existing std::vector<foo> and a type bar and rewrite it to a std::vector<bar>. The tricky part is that we also need to rewrite the allocator type. This is done via the rather complicated Rebound declaration.
Now we can write your function, and invoke it:
template <
typename ResultType,
typename C,
typename UnaryOp>
typename rebind<C, ResultType>::type
mymap(C const& c, UnaryOp op)
{
typename rebind<C, ResultType>::type result;
for(typename C::const_iterator i = c.begin();
i != c.end();
i++)
{
result.push_back(op(*i));
}
return result;
}
int main() {
vector<string> bar;
bar.push_back("1");
bar.push_back("2");
bar.push_back("3");
vector<int> foomatic =
mymap<int>(bar, [] (string s)->int {return atoi(s.c_str());});
}
Piece of cake. A really, really, complicated cake.
Answer to old question:
If you have a template parameter that is itself a class template, you need to declare it as such:
template <
template<typename> class Container,
typename ResultType,
typename UnaryOp>
Container<ResultType> mymap(Container<ResultType> c, UnaryOp op) { ... }
The template<typename> class Container mimics the class template declaration syntax and tells the compiler that “Container is a class template that expects a single template argument.”
But libraries usually avoid these nested template declarations and instead rely on traits/metafunctions to communicate such information. That is, it would usually be written as follows:
template <typename Container, typename UnaryOp>
Container mymap(Container c, UnaryOp op) {
typedef typename Container::value_type ResultType;
}
(The typename in the typedef is necessary because the name is a dependent name and C++ cannot figure out that this it names a type.)
This example mimics the standard library convention of having a typedef value_type inside each container for its associated value type. Other libraries may follow different schemas. For example, I am contributing to a library that uses external metafunctions that work as follows:
template <typename Container, typename UnaryOp>
Container mymap(Container c, UnaryOp op) {
typedef typename Value<Container>::Type ResultType;
}
The idea is the same, the only difference is that Container::value_type has been “outsourced” to an independent type.
You need something along the lines of:
template<typename Container, typename UnaryOp>
auto mymap(Container c, UnaryOp op) -> Container::rebind<decltype(op(*c.begin()))>
{
typedef typename Container::value_type InputType;
typedef decltype( op( InputType() ) ) ResultType;
typedef typename Container::rebind<ResultType> ResultContainer;
// ...
}
You can use a trick known as auto_cast, which we will rewrite a little bit to be specific to containers.
template<typename container> struct auto_cast_container {
container c;
template<typename out_type> operator out_type() {
return out_type(c.begin(), c.end());
}
};
template<typename Container, typename UnaryOperator>
auto
mymap(const Container& c, UnaryOperator op)
-> auto_cast_container<std::vector<decltype(op(*c.begin()))>> {
std::vector<decltype(op(*c.begin()))> retval;
std::for_each(c.begin(), c.end(), [&](decltype(*c.begin())& ref) {
retval.push_back(op(ref));
});
auto_cast_container<std::vector<decltype(op(*c.begin()))>> return_value;
return_value.c = std::move(retval);
return return_value;
}
Effectively, the templated conversion operator allows for conversion to any type which will accept the begin/end constructor. This means that you can map from a vector to a list, if you like, and it can also map pairs into associative containers and back again, should you need it. If you're hunting for efficiency this can be tuned further but I left that out for clarity.
Edit: Konrad's comment pointed out a couple of logical flaws. I also improved the safety and transparency of the system by using decltype in all appropriate cases.