I am new to template function and cannot figure this error. Hope you can help.
#include <iostream>
#include <vector>
/*
* Print to the screen the content of a vector
* Define function template in the header
*/
template <typename T> void print_vector(T& v) {
for(typename std::vector<T>::const_iterator i = v.begin(); i != v.end(); ++i)
std::cout << *i << ' ';
}
int main() {
std::vector<int> field;
field.resize(12, 1);
/*
for( std::vector<int>::const_iterator i = field.begin(); i != field.end(); ++i)
std::cout << *i << ' ';
*/
print_vector(field);
}
My code failed to compile with a very long error message that I can't even insert here.
error: conversion from ‘std::vector<int>::iterator {aka __gnu_cxx::__normal_iterator<int*, std::vector<int> >}’ to non-scalar type ‘std::vector<std::vector<int>, std::allocator<std::vector<int> > >::const_iterator {aka __gnu_cxx::__normal_iterator<const std::vector<int>*, std::vector<std::vector<int>, std::allocator<std::vector<int> > > >}’ requested
utility.h:21:59: error: no match for ‘operator!=’ in ‘i != (& v)->std::vector<_Tp, _Alloc>::end<int, std::allocator<int> >()’
utility.h:21:59: note: candidates are:
In file included from /usr/include/x86_64-linux-gnu/c++/4.7/./bits/c++allocator.h:34:0,
from /usr/include/c++/4.7/bits/allocator.h:48,
from /usr/include/c++/4.7/string:43,
from /usr/include/c++/4.7/bits/locale_classes.h:42,
from /usr/include/c++/4.7/bits/ios_base.h:43,
from /usr/include/c++/4.7/ios:43,
from /usr/include/c++/4.7/istream:40,
from /usr/include/c++/4.7/fstream:40,
from utility.h:4:
/usr/include/c++/4.7/ext/new_allocator.h:134:5: note: template<class _Tp> bool __gnu_cxx::operator!=(const __gnu_cxx::new_allocator<_Tp>&, const __gnu_cxx::new_allocator<_Tp>&)
/usr/include/c++/4.7/ext/new_allocator.h:134:5: note: template argument deduction/substitution failed:
utility.h:21:59: note: ‘std::vector<std::vector<int>, std::allocator<std::vector<int> > >::const_iterator {aka __gnu_cxx::__normal_iterator<const std::vector<int>*, std::vector<std::vector<int>, std::allocator<std::vector<int> > > >}’ is not derived from ‘const __gnu_cxx::new_allocator<_Tp>’
When you call
std::vector<int> field;
...
print_vector(field);
the T in print_vector1 is the type of field, i.e., std::vector<int>. Therefore the typename std::vector<T>::const_iterator in
for(typename std::vector<T>::const_iterator i = v.begin();
is a std::vector<std::vector<int> >::const_iterator, to which v.begin() (itself being a std::vector<int>::iterator) is not convertible. Use
for(typename T::const_iterator i = v.begin();
instead.
1 That is to say: in the function that's made from the function template print_vector for this case.
In your function:
template <typename T>
void print_vector(T& v) {
for(typename std::vector<T>::const_iterator i = v.begin(); i != v.end(); ++i)
std::cout << *i << ' ';
}
T is deduced as std::vector<int>, so you're trying to convert a std::vector<int>::iterator (the result of v.begin()) into a std::vector<std::vector<int>>::const_iterator (the type of i), which is not a valid conversion.
Instead, just make a more specialized template function:
template <typename T>
void print_vector(std::vector<T>& v) {
// as before
}
Either replace std::vector<T>::const_iterator i with simply T::const_iterator i if you want to pass it any iterable, or specialize it appropriately with void print_vector(std::vector<T>& v) if you wish for it to only work against vectors of any types.
If you run a substitution as you have it now you will see you are giving a vector to something creating a vector out of the type, hence getting a vector of vector.
Also GCC 4.8 and 4.9 have improved messages and add a more precise error caret.
If you can't move compiler, which is understandable, then you can always feed small snippets like that to an online one like ideone.com. The error would most likely have been a lot more concise and readable in 4.8.
Oh, and if you have access to C++11 features (I don't remember what made it in 4.7) you can auto those type declarations AND use something like cbegin() instead of begin to get the type resolution to pick a const_iterator instead of a normal one. If you're learning about templates, and have no work environment constraints, I would strongly recommend a move to C++11 and a more recent GCC, it will make easing in a lot easier.
You called the function properly. But then you confused the template-argument (type of the container) with the containers element-type.
Anyway, there's no reason for it not being const.
Thus, it should look like this instead:
template <typename T> void print_vector(const T& v) {
for(typename T::const_iterator i = v.begin(); i != v.end(); ++i)
std::cout << *i << ' ';
}
Or using the standard-library and lambdas:
template <typename T> void print_vector(const T& v) {
using std::begin; // Using ADL for begin and end to support raw arrays
using std::end;
std::for_each(begin(v), end(v), [](auto&& x){std::cout<<*i<<' ';});
}
Or using auto and range-for-loops (my favorite):
template <typename T> void print_vector(const T& v) {
for(auto&& i : v)
std::cout << *i << ' ';
}
Or using C++1z (projected for 2017):
void print_vector(const auto& v) {
for(auto&& i : v)
std::cout << *i << ' ';
}
Related
I have the following class declaration -
template <typename T>
class Polynomial{
std::map<std::string, T> _polynomial_
}
In a member function I declared an iterator for this -
typename std::map<std::string, T>::iterator it= _polynomial_.begin();
The completed member function looks like this -
template <typename T>
void Polynomial<T>::print(std::ostream& out) const
{
typename std::map<std::string, T>::iterator it= _polynomial_.begin();
std::string term;
while(it != _polynomial_.end()){
term = it->second;
term += it->first;
if(it->first < (T)0){
out << "-" << term;
}
else{
out << "+" << term;
}
term = "";
it++;
}
}
In main, I call the function as follows -
Polynomial <double> p1;
p1.add_term("x0",9.862);
std::cout << p1;
However this does not seem to work and I get errors. GCC complains of a
conversion error -
Polynomial.hpp:32:47: error: conversion from \u2018std::map, double, std::less >, std::allocator, double> > >::const_iterator {aka std::_Rb_tree_const_iterator, double> >}\u2019 to non-scalar type \u2018std::map, double, std::less >, std::allocator, double> > >::iterator {aka std::_Rb_tree_iterator, double> >}\u2019 requested
typename std::map::iterator it= polynomial.begin();
Can someone tell me what is the correct declaration of the iterator?
Polynomial<T>::print is a const member function, inside which the data member _polynomial_ becomes const too, that means what _polynomial_.begin() returns is a const_iterator, which can't be converted to iterator implicitly. (Note that std::map::begin is overloaded with const version and non-const version, the former returns const_iterator and the latter returns iterator.)
Change the code to
typename std::map<std::string, T>::const_iterator it = _polynomial_.begin();
// ^^^^^^
or use auto instead, it would deduce the correct type for you.
auto it = _polynomial_.begin();
I want to write templated function that
accepts 2 iterators
prints the content stored in container using *copy (defined in algorithm standard header).
Here is the piece of code I have written but produces compilation error
template <template<typename, typename> class Container,
typename Value,
typename Allocator = std::allocator<Value> >
void printContainer(Container<Value, Allocator>::iterator itBegin,
Container<Value, Allocator>::iterator itEnd)
{
copy(itBegin, itEnd, ostream_iterator<Value>(cout, " "));
cout << endl;
}
Error produced are :
error 1: variable or field ‘printContainer’ declared void
void printContainer(Container<Value, Allocator>::iterator itBegin,
^
error 2: expected ‘)’ before ‘itBegin’
void printContainer(Container<Value, Allocator>::iterator itBegin,
^
error 3: expected ‘)’ before ‘itEnd’
Container<Value, Allocator>::iterator itEnd)
^
p00441.cpp: In function ‘int main()’:
p00441.cpp:10:39: error: ‘printContainer’ was not declared in this scope
printContainer(inp.begin(), inp.end());
Another snippet I wrote is
template<typename InputIterator>
void printContainer(InputIterator itBegin, InputIterator itEnd){
//Trial 1
copy(itBegin, itEnd, ostream_iterator< iterator_traits<ForwardIterator1>::value_type>(cout, " "));
//Trial 2
copy(itBegin, itEnd, ostream_iterator<value_type(itBegin)*>(cout, " "));
cout << endl;
}
Error produced are :
error 1: ‘ForwardIterator1’ was not declared in this scope
copy(itBegin, itEnd, ostream_iterator< iterator_traits<ForwardIterator1>::value_type>(cout, " "));
^
error 2: template argument 1 is invalid
copy(itBegin, itEnd, ostream_iterator< iterator_traits<ForwardIterator1>::value_type>(cout, " "));
^
error 3: template argument 1 is invalid
copy(itBegin, itEnd, ostream_iterator< iterator_traits<ForwardIterator1>::value_type>(cout, " "));
^
error 3: type/value mismatch at argument 1 in template parameter list for ‘template<class _Tp, class _CharT, class _Traits> class std::ostream_iterator’
copy(itBegin, itEnd, ostream_iterator<value_type(itBegin)*>(cout, " "));
^
error 4: expected a type, got ‘(value_type(itBegin) * <expression error>)’
Please elaborate what errors mean and their cause of occurrence. Also suggest how to achieve the desired goal.
I will be grateful if you could suggest some sources for a novice to understand iterators.
Regarding your first question, you can simply use the iterator as the template type and use iterator::value_type:
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
#include <iterator>
using namespace std;
template <typename Iterator>
void printContainer(Iterator itBegin,
Iterator itEnd)
{
copy(itBegin, itEnd, ostream_iterator<typename Iterator::value_type>(cout, " "));
cout << endl;
}
int main() {
vector<int> v{1, 2, 3, 4, 5, 6};
list<int> l{1, 2, 3, 4, 5, 6};
printContainer(begin(v), end(v));
printContainer(begin(l), end(l));
return 0;
}
https://ideone.com/DhUQ1t
Using iterator_traits also works and is a better solution since it will also work for pointers (that naturally do not have the value_type member; thanks to Jarod42 for pointing this out):
template <typename Iterator>
void printContainer(Iterator itBegin,
Iterator itEnd)
{
copy(itBegin, itEnd, ostream_iterator<typename iterator_traits<Iterator>::value_type>(cout, " "));
cout << endl;
}
https://ideone.com/8N0ook
Starting with C++14, you can also use decltype and decay_t:
template <typename Iterator>
void printContainer(Iterator itBegin,
Iterator itEnd)
{
copy(itBegin, itEnd, ostream_iterator<decay_t<decltype(*itBegin)>>(cout, " "));
cout << endl;
}
https://ideone.com/7MBsiL
Regarding your other tries, there's no ForwardIterator1 defined in your function and value_type is a typedef, not a function.
Inspired by Antony's Williams "C++ Concurrency in Action" I wanted to take a closed look at his thread safe hash map. I copied its code and added some output operators and this is what I came up with:
#include <boost/thread/shared_mutex.hpp>
#include <functional>
#include <list>
#include <mutex>
#include <iostream>
template <typename Key, typename Value, typename Hash = std::hash<Key>>
class thread_safe_hashmap
{
private:
class bucket_type
{
public:
typedef std::pair<Key, Value> bucket_value;
typedef std::list<bucket_value> bucket_data;
typedef typename bucket_data::iterator bucket_iterator;
bucket_data data;
mutable boost::shared_mutex mutex;
bucket_iterator find_entry_for(const Key& key) const
{
return std::find_if(data.begin(), data.end(),
[&](const bucket_value& item) { return item.first == key; });
}
public:
void add_or_update_mapping(Key const& key, Value const& value)
{
std::unique_lock<boost::shared_mutex> lock(mutex);
bucket_iterator found_entry = find_entry_for(key);
if (found_entry == data.end())
{
data.push_back(bucket_value(key, value));
}
else
{
found_entry->second = value;
}
}
};
std::vector<std::unique_ptr<bucket_type>> buckets;
Hash hasher;
bucket_type& get_bucket(Key const& key) const
{
std::size_t const bucket_index = hasher(key) % buckets.size();
return *buckets[bucket_index];
}
template <typename Key2, typename Value2>
friend std::ostream& operator<<(std::ostream& os, const thread_safe_hashmap<Key2, Value2>& map);
public:
thread_safe_hashmap(unsigned num_buckets = 19, Hash const& hasher_ = Hash())
: buckets(num_buckets), hasher(hasher_)
{
for (unsigned i = 0; i < num_buckets; ++i)
{
buckets[i].reset(new bucket_type);
}
}
thread_safe_hashmap(thread_safe_hashmap const& other) = delete;
thread_safe_hashmap& operator=(thread_safe_hashmap const& other) = delete;
void add_or_update_mapping(Key const& key, Value const& value)
{
get_bucket(key).add_or_update_mapping(key, value);
}
};
template <typename First, typename Second>
std::ostream& operator<<(std::ostream& os, const std::pair<First, Second>& p)
{
os << p.first << ' ' << p.second << '\n';
return os;
}
template <typename Key, typename Value>
std::ostream& operator<<(std::ostream& os, const thread_safe_hashmap<Key, Value>& map)
{
for (unsigned i = 0; i < map.buckets.size(); ++i)
{
for (const auto el : map.buckets[i]->data) os << el << ' ';
os << '\n';
}
return os;
}
int main()
{
thread_safe_hashmap<std::string, std::string> map;
map.add_or_update_mapping("key1", "value1"); // problematic line
std::cout << map;
}
The marked line is causing problems on both gcc and clang:
clang++ -Wall -std=c++14 main2.cpp -lboost_system -o main
main2.cpp:24:14: error: no viable conversion from returned value of type 'std::_List_const_iterator<std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >' to function
return type 'bucket_iterator' (aka '_List_iterator<std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >')
return std::find_if(data.begin(), data.end(),
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main2.cpp:32:37: note: in instantiation of member function 'thread_safe_hashmap<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, std::hash<string> >::bucket_type::find_entry_for'
requested here
bucket_iterator found_entry = find_entry_for(key);
^
main2.cpp:71:21: note: in instantiation of member function 'thread_safe_hashmap<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, std::hash<string>
>::bucket_type::add_or_update_mapping' requested here
get_bucket(key).add_or_update_mapping(key, value);
^
main2.cpp:98:7: note: in instantiation of member function 'thread_safe_hashmap<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, std::hash<string> >::add_or_update_mapping'
requested here
map.add_or_update_mapping("key1", "value1");
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.1/../../../../include/c++/5.3.1/bits/stl_list.h:125:12: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from
'std::_List_const_iterator<std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >' to 'const std::_List_iterator<std::pair<std::__cxx11::basic_string<char>,
std::__cxx11::basic_string<char> > > &' for 1st argument
struct _List_iterator
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.3.1/../../../../include/c++/5.3.1/bits/stl_list.h:125:12: note: candidate constructor (the implicit move constructor) not viable: no known conversion from
'std::_List_const_iterator<std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >' to 'std::_List_iterator<std::pair<std::__cxx11::basic_string<char>,
std::__cxx11::basic_string<char> > > &&' for 1st argument
1 error generated.
melpon's online demo
What am I missing here?
This is the expected behavior. In find_entry_for you're trying to return const_iterator, which doesn't match the return type iterator.
find_entry_for is const member function, for data.begin(), data will be const std::list<bucket_value>, begin() called on it will return const_iterator. And std::find_if will return the same type with the type of the parameter iterator, i.e. const_iterator, which could not be implicitly converted to the return type of find_entry_for, i.e. bucket_iterator (std::list::iterator).
Because the returned iterator might be used to change the value it points to, you could
Change find_entry_for to non-const member function. (Or add it as new overloading function, change the original const member function's return type to const_iterator.)
Try to convert const_iterator to iterator before returns.
bucket_iterator is defined the following way
typedef typename bucket_data::iterator bucket_iterator;
That is it is not a constant iterator.
However in member function find_entry_for
bucket_iterator find_entry_for(const Key& key) const
{
return std::find_if(data.begin(), data.end(),
[&](const bucket_value& item) { return item.first == key; });
}
standard algorithm std::find_if uses the constant iterator because this member function is declared with qualifier const and there are used overloaded functions begin and end for the constant data member data.
So you need to define the constant iterator in the class and use it as the return type of the function.
For example
typedef typename bucket_data::const_iterator const_bucket_iterator;
First time using Boost, and trying to grok how to use boost::variant. Please find below an example program and the error message (GCC v5.3.0, -std=c++14)
#include <vector>
#include <iostream>
#include <sstream>
#include <boost/variant.hpp>
using int_tree_t =
boost::make_recursive_variant <
int,
std::vector<boost::recursive_variant_>>;
auto operator << (std::ostream& out, const int_tree_t& tree) ->
std::ostream&
{
struct stringify :
public boost::static_visitor <std::string>
{
public:
auto operator () (int i) const ->
std::string
{
return std::to_string (i);
}
auto operator () (const std::vector<int_tree_t>& vec) const ->
std::string
{
std::stringstream ss;
ss << "(";
auto it = std::begin (vec);
if (!vec.empty ()) {
ss << *it;
}
for (; it != std::end (vec); ++it) {
ss << " " << *it;
}
ss << ")";
return ss.str ();
}
};
std::stringstream ss;
ss.flags (out.flags ());
ss << boost::apply_visitor (stringify (), tree);
return (out << ss.str ());
}
Error message:
In file included from /usr/local/include/boost/variant/apply_visitor.hpp:16:0,
from /usr/local/include/boost/variant/detail/hash_variant.hpp:23,
from /usr/local/include/boost/variant/variant.hpp:34,
from /usr/local/include/boost/variant.hpp:17,
from test2.cpp:5:
/usr/local/include/boost/variant/detail/apply_visitor_unary.hpp: In instantiation of ‘typename Visitor::result_type boost::apply_visitor(const Visitor&, Visitable&) [with Visitor = operator<<(std::ostream&, const int_tree_t&)::stringify; Visitable = const boost::make_recursive_variant<int, std::vector<boost::recursive_variant_, std::allocator<boost::recursive_variant_> > >; typename Visitor::result_type = std::__cxx11::basic_string<char>]’:
test2.cpp:50:43: required from here
/usr/local/include/boost/variant/detail/apply_visitor_unary.hpp:84:43: error: ‘const struct boost::make_recursive_variant<int, std::vector<boost::recursive_variant_, std::allocator<boost::recursive_variant_> > >’ has no member named ‘apply_visitor’
return visitable.apply_visitor(visitor);
^
If I understand correctly, boost::make_recursive_variant is supposed to create a type which acts identical to boost::variant... but the error message appears to indicate that it doesn't have the apply_visitor function, which is necessary for visitation. I've read over [this(http://www.boost.org/doc/libs/1_60_0/doc/html/variant/tutorial.html) page, but there's nothing there about having to use a "special" visitation pattern with recursive variants.
How should I be writing this program?
make_recursive_variant is a metafunction, not a type in its own right. So you have to evaluate the metafunction:
using int_tree_t =
boost::make_recursive_variant <
int,
std::vector<boost::recursive_variant_>>::type;
↑↑↑↑↑↑
Otherwise, you're using a metafunction type instead of a variant type.
I'm trying to write a function to print a representation of common STL containers (vector, list, etc..). I gave the function a template parameter T which, for example, might represent vector. I'm having problems getting an iterator of type T.
vector<int> v(10, 0);
repr< vector<int> >(v);
...
template <typename T>
void repr(const T & v)
{
cout << "[";
if (!v.empty())
{
cout << ' ';
T::iterator i;
for (i = v.begin();
i != v.end()-1;
++i)
{
cout << *i << ", ";
}
cout << *(++i) << ' ';
}
cout << "]\n";
}
...
brett#brett-laptop:~/Desktop/stl$ g++ -Wall main.cpp
main.cpp: In function ‘void repr(const T&)’:
main.cpp:13: error: expected ‘;’ before ‘i’
main.cpp:14: error: ‘i’ was not declared in this scope
main.cpp: In function ‘void repr(const T&) [with T = std::vector<int, std::allocator<int> >]’:
main.cpp:33: instantiated from here
main.cpp:13: error: dependent-name ‘T::iterator’ is parsed as a non-type, but instantiation yields a type
main.cpp:13: note: say ‘typename T::iterator’ if a type is meant
I tried 'typename T::iterator' as the compiler suggested, but only got a more cryptic error.
Edit: Thanks for the help guys! Here's a working version for anyone who wants to use this function:
template <typename T>
void repr(const T & v)
{
cout << "[";
if (!v.empty())
{
cout << ' ';
typename T::const_iterator i;
for (i = v.begin();
i != v.end();
++i)
{
if (i != v.begin())
{
cout << ", ";
}
cout << *i;
}
cout << ' ';
}
cout << "]\n";
}
You need typename to tell the compiler that ::iterator is supposed to be a type. The compiler doesn't know that it's a type because it doesn't know what T is until you instantiate the template. It could also refer to some static data member, for example. That's your first error.
Your second error is that v is a reference-to-const. So, instead of ::iterator you have to use ::const_iterator. You can't ask a constant container for a non-const iterator.
Change T::iterator i; to typename T::const_iterator i; because ::iterator is of type T and v is a const &.
Before a qualified dependent type, you need typename.
Without typename, there is a C++ parsing rule that says that qualified dependent names should be parsed as non-types even if it leads to a syntax error.
typename states that the name that follows should be treated as a type. Otherwise, names are interpreted to refer to non-types.
Maybe this will help:
Typename is mandatory before a qualified-dependent name which refers to a type, unless that name is naming a base class, or in an initialization list. Typename is optional before a qualified (but non-dependent name) is used within a template, except again when naming a base class or in an initialization list.