Removing cv-qualifier from templated vector function - c++

I'm writing some code that randomly picks an element from a given vector with any generic type. I've successfully made a function that returns a copy of a random element, but it'd be convenient for me if there's a similar function that returns the iterator of that element instead. This is what I have, in which the random iterator is yielded from adding a random number to the begin iterator through a generator function:
template <class T>
typename std::vector<T>::iterator pickElementIterator(const std::vector<T>& v)
{
if (v.empty())
{
// error
return v.end();
}
return v.begin() + generate(v.size());
}
This compiles successfully if no code uses it. But as soon as I try to substitute in some vector with type Foo, the following error comes up using g++:
could not convert '(& v)->std::vector::end()' from '__normal_iterator<const Foo*,[...]>' to
__normal_iterator<Foo*,[...]>'
For both returns. It seems it adds a const to the type when attempting to convert it for returning. I've tried std::decay on both returns but it does not accept those arguments. That's as far as my knowledge on template programming goes, and not much about this is found anywhere I looked.
Note: "typename" is in the return type because otherwise g++ complains with:
need 'typename' before 'std::vector<_RealType>::iterator' because 'std::vector<_RealType>' is a dependent scope
Which is still not clear for me.

std::vector<T>::begin()/std::vector<T>::end() return a const_iterator when const qualified, not an iterator (which is mutable).
The reason this fails to compile is because const_iterators cannot be converted to mutable iterator types. The fix is simple: change the return type to be const_iterator:
template <class T>
typename std::vector<T>::const_iterator pickElementIterator(const std::vector<T>& v)
// ^~~~~~~~~~~~~~
If you're in c++14 or above, you can also just use auto without a declared return type so that it can deduce it itself, e.g.:
template <class T>
auto pickElementIterator(const std::vector<T>& v)
Note: The reason you observed that this compiled successfully when not used is because templates can't fully be evaluated until instantiated. The compiler has to assume that anything that relies on a template parameter (for example, type T) might produce a valid instantiation thanks to template specialization.
For example, the compiler must assume that there may exist a T such that const std::vector<T>::begin() returns something which could construct a std::vector<T>::iterator. This could happen if vector<T> were specialized.
As a result, you won't often see many diagnostics outside of syntax errors until you're actually instantiating a template

I suggest that you let auto decide what kind of iterator that is returned. If you use C++11 you can use a trailing return type like decltype(v.begin()) and in C++14 and later, that's not needed.
If you also make use of template template parameters, you don't have to make it work for vectors only. v.begin() + generate(v.size()) requires random access though, so I suggest using std::next to get the resulting iterator.
Example:
#include <iterator> // std::next
template <template <class, class...> class C, class T, class... Args>
auto pickElementIterator(const C<T, Args...>& c) -> decltype(c.begin()) {
if(c.empty()) return c.end();
return std::next(c.begin(), generate(c.size()));
}

Related

Creating a function that returns true if element is in unordered_set, how to deal with templates?

I have this unordered_set:
std::unordered_set<Category, CategoryHash, CategoryEqual>
I have to do this:
if (allowTheseCategories->find(message.category) != allowTheseCategories->end())
in order to find if an element exists in the unordered_set
I wanted to write a function that returns true or false if element exists in unordered_set, but I quickly figured out that it'd have to deal with types:
template <typename T, Typename U, typename V>
bool unorderedSetHasElement(std::unordered_set<T, U, V>& unorderedSet, T element) {
return unorderedSet->find(element) != unorderedSet->end()
}
and calling this function would not be pratical, since I'd have to do:
if (unorderedSetHasElement<Category, CategoryHash, CategoryEqual>(...))
Is there any way to create a simple function that accepts unordered_set? Or is there a way to extend unordered_set to have this function?
I think you may find that you do not have to include the template parameters every time you call a templated function. Your compiler should be able to deduce the types automatically. The following code is valide c++ if you fill in the ...'s.
std::unordered_set<Category, CategoryHash, CategoryEqual> my_set(...);
if (unorderedSetHasElement(my_set, ...)){
...
}
EDIT: You may be interested in writing the function for any associative container. Here is a simple version.
template <typename Container, typename ContinerKey>
bool Contains(Container& cont, ContinerKey key)
{
return cont.find(key) != cont.end();
}
Note in this version I am ignoring the template parameters of the container. You do not have to have them, but the compiler will blow up with lots of unreadable errors if you do not use it correctly. For more complex versions you may want to use type traits to determine if the type is an associative container.

Template metaprogramming help: transforming a vector

As my first template metaprogram I am trying to write a function that transforms an input vector to an output vector.
For instance, I want
vector<int> v={1,2,3};
auto w=v_transform(v,[](int x){return (float)(x*2)})
to set w to the vector of three floats, {2.0, 4.0, 6.0} .
I started with this stackoverflow question, The std::transform-like function that returns transformed container , which addresses a harder question of transforming arbitrary containers.
I now have two solutions:
A solution, v_transform_doesntwork that doesn’t work, but I don’t know why (which I wrote myself).
A solution, v_transform that works, but I don’t know why (based on Michael Urman's answer to the above question)
I am looking for simple explanations or pointers to literature that explains what is happening.
Here are the two solutions, v_transform_doesntwork and v_transform:
#include <type_traits>
#include <vector>
using namespace std;
template<typename T, typename Functor,
typename U=typename std::result_of<Functor(T)>::type>
vector<U> v_transform(const std::vector<T> &v, Functor&& f){
vector<U>ret;
for(const auto & e:v)
ret.push_back(f(e));
return ret;
}
template<typename T, typename U>
vector<U> v_transform_doesntwork(const std::vector<T> &v, U(*f)(const T &)){
vector<U>ret;
for(const auto & e:v)
ret.push_back(f(e));
return ret;
}
float foo(const int & i){
return (float)(i+1);
}
int main(){
vector<int>v{1,2,3,4,5};
auto w=v_transform(v,foo);
auto z=v_transform(v,[](const int &x){return (float)(x*2);});
auto zz=v_transform(v,[](int x){return (float)(x*3);});
auto zzz=v_transform_doesntwork(v,[](const int &x){return (float)(x*2);});
}
Question 1: why doesn’t the call to v_transform_doesntwork compile? (It gives a fail-to-match template error, c++11. I tried about 4 permutations of “const” and “&” and “*” in the argument list, but nothing seemed to help.)
I prefer the implementation of v_transform_doesntwork to that of v_transform, because it’s simpler, but it has the slight problem of not working.
Question 2: why does the call to v_transform work? I get the gist obviously of what is happening, but I don’t understand why all the typenames are needed in defining U, I don’t understand how this weird syntax of defining a template parameter that is relied on later in the same definition is even allowed, or where this is all specified. I tried looking up "dependent type names" in cppreference but saw nothing about this kind of syntax.
Further note: I am assuming that v_transform works, since it compiles. If it would fail or behave unexpectedly under some situations, please let me know.
Your doesnotwork expects a function pointer and pattern matches on it.
A lambda is not a function pointer. A stateless lambda can be converted to a function pointer, but template pattern matching does not use conversions (other than a very limited subset -- Derived& to Base& and Derived* to Base&, reference-to-value and vice versa, etc -- never a constructor or conversion operator).
Pass foo to doesnotwork and it should work, barring typos in your code.
template<typename T,
typename Functor,
typename U=typename std::result_of<Functor(T)>::type
>
vector<U> v_transform(const std::vector<T> &v, Functor&& f){
vector<U>ret;
for(const auto & e:v)
ret.push_back(f(e));
return ret;
}
so you call v_transform. It tries to deduce the template types.
It pattern matches the first argument. You pass a std::vector<int, blah> where blah is some allocator.
It sees that the first argument is std::vector<T>. It matches T to int. As you did not give a second parameter, the default allocator for std::vector<T> is used, which happens to match blah.
We then continue to the second parameter. You passed in a closure object, so it deduces the (unnamable) lambda type as Functor.
It is now out of arguments to pattern match. The remaining types use their defaulted types -- U is set to typename std::result_of<Functor(T)::type. This does not result in a substitution failure, so SFINAE does not occur.
All types are determined, and the function is now slotted into the set of overloads to examine to determine which to call. As there are no other functions of the same name, and it is a valid overload, it is called.
Note that your code has a few minor errors:
template<typename T,
typename A,
typename Functor,
typename U=typename std::decay<typename std::result_of<Functor&(T const&)>::type>::type
>
std::vector<U> v_transform(const std::vector<T, A> &v, Functor&& f){
std::vector<U> ret;
ret.reserve(v.size());
for(const auto & e:v)
ret.push_back(f(e));
return ret;
}
which cover some corner cases.
Question 1
Why doesn't the call to v_transform_doesntwork compile?
This is because you've passed it a C++11 lambda. The template argument in v_transform_doesntwork is a function pointer argument. C++11 lambdas are, in fact, objects of an unknown type. So the declaration
template<typename T, typename U>
vector<U> v_transform_doesntwork(const std::vector<T> &v, U(*f)(const T &))
binds T to the input type of the function pointer f and U to the output type of the function pointer. But the second argument cannot accept a lambda for this reason! You can specify the types explicitly to make it work with the non-capturing lambda, but the compiler will not attempt the type inference in the face of the cast.
Question 2
Why does the call to v_transform work?
Let's look at the code you wrote:
template<typename T,
typename Functor,
typename U=typename std::result_of<Functor(T)>::type>
vector<U> v_transform(const std::vector<T> &v, Functor&& f){
Again, T is a template parameter that represents the input type. But now Functor is a parameter for whichever callable object you decide to pass in to v_transform (nothing special about the name). We set U to be equal to the result of that Functor being called on T. The std::result_of function jumps through some hoops to figure out what the return value will be. You also might want to change the definition of U to
typename U=typename std::result_of<Functor&(T const &)>::type>
so that is can accept functions taking constants or references as parameters.
For the doesntwork function, you need to explicitly specify the template parameters:
auto zzz=v_transform_doesntwork<int,float>(v,[](const int &x){return (float)(x*2);});
Then it does work. The compiler is not able to implicitly determine these parameters whilst it converts the lambda to a function pointer.

"typename vector<T>::iterator" does not recognized by compiler

Now I have a template method like this:
template<typename T>
void f(typename vector<T>::iterator it)
{
//implemenation
...
}
int main()
{
vector<int> v;
//initialization of v;
...
f(v.begin());
return 0;
}
But when I compile as "g++ THIS_FILE -o TARGET_RUNNABLE", the compile says
no matching function for call to ‘f(std::vector<int>::iterator)’
template argument deduction/substitution failed:
couldn't deduce template parameter ‘T’
I do realize to add keyword "typename" before vector::iterator. But it is still wrong. Does anybody know how to fix this problem?
Your function takes an iterator, but you are trying to pass a vector. You might have meant f(v.begin()) or something like that.
Also, as #chris notes, T is in a non-deducible context. It would have to be provided explicitly, as in f<int>(v.begin());
The problem is that Template Argument Deduction works on about 20 different forms, but not the form typename Foo<T>::Bar. The reason is that there are infinitely many Foos, and each of them could have a nested type Bar which matches yours. The compiler can't search all of them.
A good example of such a problem is std::vector<T>::const_iterator versus std::vector<const T>::const_iterator, which might very well be the same type.
It's therefore called a non-deduced context. You have to be explicit which template you want .
One way to fix the compiler error is to be explicit about the template parameter.
f<int>(v.begin());
You passed v which is vector<int> to function f. You should pass iterator to f.
Just redesign your template function to
template<typename Iterator>
void f(Iterator it)
{
// manipulate iterator it
}
then you could call
vector<int> v;
f(v.begin());

Pass Templated iterator for STL Container

For an exercise for my C++ class (which hasn't covered Boost yet), I am having trouble writing a templated method to accept two iterators for summing numeric values in an STL container.
Consider the following example:
#include <iostream>
#include <iterator>
#include <vector>
template<typename T>
double Sum(const T & c) {
return 42.0; // implementation stubbed
}
// need help writing this method signature to accept two iterators
template<typename T>
double Sum(const typename T::const_iterator & begin,
const typename T::const_iterator & end) {
return 43.0; // another implementation stub
}
int main() {
std::vector<double> v;
v.push_back(3.14);
v.push_back(2.71);
v.push_back(1.61); // sums to 7.46
std::cout << Sum(v) << ' ' // line 23
<< Sum(v.begin(), v.end()) // line 24
<< '\n';
}
I expect this code to output 42 43, but it fails to compile.
The error g++ gives me is:
test_exercise2.cpp: In function ‘int main()’:
test_exercise2.cpp:24: error: no matching function for call to ‘Sum(__gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > >, __gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > >)’
If I comment out line 24, I get 42 as the output, as expected.
I get the same error message whether or not the second templated method is present or not, so for some reason, it's not able to resolve the call on line 24 to the second method I wrote.
What signature must I have for the method that accepts two iterators?
The reason why I'm stuck on this is because I need to support summing over the second element of std::map<K, V>. This will require two more overloads to call ->second instead of dereferencing the iterator:
1. template<typename K, typename V> double Sum(const std::map<K, V> & m); (I'm okay with this one)
2. and another one involving iterators over the map.
I feel like I'll be able to write the methods for std::map if I can figure out how to specify the passing of iterators for std::list and std::map. I'm okay with solutions that use template-templates.
EDIT: The precise wording of problem (omitting non-contributory sentences).
The containers from "the previous exercise" were std::vector<double>, std::list<double>, std::map<std::string, double>.
Create a template function called Sum() that accepts the template
argument T as input and returns a double. The template argument will
be a container.
In the implementation get an iterator (T::const_iterator) for the end. Then create a loop that iterates the container T and adds all
values. Finally return the sum.
In the main program, call the Sum() function for the different container from the previous exercise.
The Sum() function created calculates the sum of the complete
container. Also create a Sum() function that calculates the sum
between two iterators. The function then uses the template argument
for the iterator type and accepts two iterators, the start and end
iterator.
You're overcomplicating this. You want a pair of iterators of any type? Well, that's just as simple as .. two arguments, of any type.
template<typename Iterator>
double Sum(const Iterator& begin,
const Iterator& end) {
return 43.0; // another implementation stub
}
Problem solved.
By the way, take a hint from the C++ Standard lib: If you can't de-reference the iterator, make the user provide a function to get the value from the iterator. Don't special-case std::map because tomorrow there's std::unordered_map and the day after that boost::multimap and all sorts of fun. And what if I wanted you to sum the keys from the std::map, not the values?
Your hardcoded case is a little more complex. A pair of iterators that have to come from std::map? Not even sure if possible without explicit template arguments.
template<typename K, typename V, typename Comp, typename Alloc>
double Sum(
const std::map<K, V, Comp, Alloc>& map
) { ... }
Notice that I specifically said it had to be a std::map instantiation. This allows the compiler to deduce the parameters. From here, you can access the iterators.
As DeadMG said, the simple way is to template on the type of the iterator. The common convention is, on the other hand, to pass iterators by value:
template <typename Iterator>
double Sum( Iterator begin, Iterator end );
As to why the original code was not working, the problem is that the type of the container is not deducible:
template <typename T>
double Sum( T::const_iterator begin, T::const_iterator end );
Sum( v.begin(), v.end() ); // [*] Assume v == const std::vector<double>&
When the compiler tries to infer the type of the arguments to Sum it only sees the type returned by v.begin() and v.end(), which are the iterator. From that type, it cannot guess the type of the container. To be able to determine what the type T is, it would have to test all non template types, and generate all infinite possible instantiations of template types to look whether they have a nested type const_iterator that matches the type of v.begin() and v.end(). Because that would be impossible, to achieve, the language forbids it in the first place.
Beyond that, and related to the comment [*], even if the type would be deducible, overload resolution is performed on the arguments to the function, and not how the expression is later use. In your program, the argument to .begin() is a std::vector<double> non-const lvalue. Because it is not const, the overload selected will yield a non-const iterator (even if in the function you want to call, there is no need to read it).
The distinguishing feature when contrasting iterators from e.g. std::list with iterators from std::map is that the latter have a pair type as their value_type. That is to say, given std::map<K, V> then both std::map<K, V>::value_type and std::iterator_traits<std::map<K, V>::iterator>::value_type are std::pair<const K, V>.
Hence I suggest your Sum template accept any iterator, but that it operates not on elements given from the iterator (i.e. *it) and instead on a 'view': element(*it). Now you can take care to make sure that element 'does the right thing' when faced with a pair.
As a hint, you could declare Sum as the following (with a bit of metaprogramming for getting the return type correctly):
namespace result_of {
// Second template parameter is an implementation detail
template<
typename Iterator
, typename ValueType = typename std::iterator_traits<Iterator>::value_type
>
struct Sum {
// general case: sum over the value type directly
typedef ValueType type;
};
// If an iterator admits an std::pair as its value_type then we end up here
template<typename Iterator, typename Key, typename Value>
struct Sum<Iterator, std::pair<Key, Value> > {
// special case: sum over the second type of the value
typedef Value type;
};
} // result_of
template<typename Iterator>
typename result_of::Sum<Iterator>::type Sum(Iterator begin, Iterator end);

Implementing a map_keys_iterator by derivation: a single compiler error

I was working again with C++ during the weekend and came to notice something that I'm not sure where does it come from.
Following the advice in this thread, I decided to implement a map_keys_iterator and map_values_iterator. I took the -- I think -- recommended-against approach of deriving a class from std::map<K,V>::iterator and implementing it as such:
template <typename K, typename V>
struct map_values_iterator:
public std::map<K,V>::iterator {
// explicitly call base's constructor
typedef typename std::map<K,V>::iterator mIterator;
map_values_iterator (const mIterator& mi) :
mIterator(mi) {};
const V& operator* () const { return (*this)->second; }
};
So far, so good, and the following code works (nvm the Unicode, I default to work with i18n-capable terminals):
typedef std::map<double,string> Map;
Map constants;
constants[M_PI] = "π";
constants[(1+sqrt(5))/2] = "φ";
constants[exp(M_PI)-M_PI] = "fake_20";
// ... fill map with more constants!
map_values_iterator<double, std::string> vs(constants.begin());
for (; vs != m.end(); ++vs) {
cout<< (vs != m.begin() ? ", " : "")<< *vs;
}
cout<< endl;
This code prints the expected result, something like (because a Map's elements are ordered):
..., φ, ..., π, ...., fake_20, ....
So I'd guess a map_keys_iterator would work in a similar way as well. I took the care that a Map's value_type is actually pair<const K, V> so the keys version will return a value.
However, it is unwieldly to have to declare the iterator's type so I wanted to create a caller with the classical make_pair-like idiom. And this is where trouble begins:
template <typename K, typename V>
map_values_iterator<K,V> map_values(const typename std::map<K,V>::iterator &i) {
return lpp::map_values_iterator<K,V> (i);
}
template <typename K, typename V>
map_values_iterator<K,V> map_values(const typename std::map<K,V>::const_iterator &i) {
return lpp::map_values_iterator<K,V> (i);
}
I'm relatively sure this function has the right signature and constructor invocation. However if I attempt to call the function from code:
auto vs= map_values(constants.begin());
I get a single STL compiler error of the form:
error: no matching function for call to ‘map_values(std::_Rb_tree_iterator<std::pair<const double, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >)’
I'm assuming here that in this particular case the whole _Rb_tree_iterator is actually the correct iterator for which map::iterator is typedefed; I'm not completely sure however. I've tried to provide more overloads to see if one of them matches (drop the reference, drop the const, use only non-const_iterator variants, etc) but so far nothing allows the signature I'm interested in.
If I store the base iterator in a variable before calling the function (as in auto begin= constans.begin(); auto vs= map_values(begin);) I get the exact same base error, only the description of the unmatched call is obviously different (in that it is a "const blah&").
My first attempt at implementing this sort of iterator was by creating a base class that aggregated map::iterator instead of inheriting, and deriving two classes, each with the adequate operator*, but that version ran into many more problems than the above and still forced me to replicate too much of the interface. So I tried this option for code-expedition.
I've tried to look for answers to this issue but my Google-fu isn't very strong today. Maybe I am missing something obvious, maybe I forgot something with the derivation (although I'm almost sure I didn't -- iterators are unlike containers), maybe I am actually required to specify all the template parameters for the map, or maybe my compiler is broken, but whatever it is I can't find it and I am having real trouble understanding what is the actual thing the compiler is complaining about here. In my previous experience, if you are doing something wrong with the STL you are supposed to see a diarrhoea of errors, not only one (which isn't STL to boot).
So... any (well-encapsulated) pointers would be appreciated.
The reason is that your K and V type parameters are in a non-deducible context, so your function template is never even instantiated during overload resolution.
Look at it again:
template <typename K, typename V>
map_keys_iterator<K,V> map_keys(const typename std::map<K,V>::iterator &i)
For this to work, the C++ compiler would somehow have to walk from a specific iterator class to its "parent container" type - map in this case - to get its K and V. In general, this is impossible - after all, a particular iterator might be a typedef for some other class, and the actual type of argument in the call is that other class; there's no way the compiler can "retrace" it. So, per C++ standard, it doesn't even try in this case - and, more generally, in any case where you have typename SomeType<T>::OtherType, and T is a type parameter.
What you can do is make the entire parameter type a template type parameter. This requires some trickery to derive K and V, though.
template <typename Iterator>
map_keys_iterator<
typename std::iterator_traits<Iterator>::value_type::first_type,
typename std::iterator_traits<Iterator>::value_type::second_type
> map_keys(Iterator i)
Unfortunately, you'll have to repeat those two in the body of the function as well, when invoking the constructor of your type.
As a side note, iterators are generally passed by value (they're meant to be lightweight).