HI,
I don't like posting compile problems, but I really can't figure this one out. Using this code:
#include <map>
#include <boost/iterator/transform_iterator.hpp>
using namespace std;
template <typename K, typename V>
struct get_value
{
const V& operator ()(std::pair<K, V> const& p) { return p.second; }
};
class test
{
typedef map<int, float> TMap;
TMap mymap;
public:
typedef get_value<TMap::key_type, TMap::value_type> F;
typedef boost::transform_iterator<F, TMap::iterator> transform_iterator;
transform_iterator begin()
{
return make_transform_iterator(mymap.begin(), F());
}
};
Getting this compile error:
transform_iterator.hpp(43) : error C2039: 'result_type' : is not a member of 'get_value<K,V>'
with
[
K=int,
V=std::pair<const int,float>
]
Can anyone explain why this isn't working? I'm using Visual Studio 7.0 with boost 1.36.0
Thanks.
Since you also asked for an explanation
The transform_iterator needs to know the return type of the function called in order to instantiate itself. This is determined via result_of (found in <boost/utility/result_of.hpp>
If you use a function object, you need to define a member result_type to specify the result type of the object. (since an object doesn't have a 'return type' as such)
If you would have used a regular function, result_of would be able to figure it out on his own, e.g.:
template <typename K, typename V>
const V & get_value(std::pair<K, V> const & p) { return p.second; }
class test
{
typedef map<int, float> TMap;
TMap mymap;
public:
typedef boost::function< const TMap::mapped_type & (const TMap::value_type &) > F;
typedef boost::transform_iterator<F, TMap::iterator> transform_iterator;
transform_iterator begin()
{
return boost::make_transform_iterator(mymap.begin(), &get_value< int, float >);
}
};
You'll have to inherit get_value from unary_function<const V&, std::pair<K, V> const&> to tell transform_iterator what the signature of get_value is.
// here is a working example:
#include <vector>
#include <iostream>
#include <boost/iterator/transform_iterator.hpp>
template <typename T, typename U>
const T& Get1st(const std::pair<T, U>& pair) { return pair.first; }
struct Bar {
using Pairs = std::vector<std::pair<int, char>>;
using Iter = boost::transform_iterator< decltype(&Get1st<int, char>), Pairs::const_iterator >;
void add(int i, char c) { _pairs.emplace_back(i, c); }
Iter begin() { return boost::make_transform_iterator(_pairs.begin(), &Get1st<int, char>); }
Iter end() { return boost::make_transform_iterator(_pairs.end(), &Get1st<int, char>); }
private:
Pairs _pairs;
};
int main() {
Bar bar;
bar.add(1, 'a');
bar.add(3, 'c');
bar.add(2, 'b');
for(const auto& i : bar) std::cout << i << " ";
std::cout << "\n";
return 0;
}
// outputs: 1, 3, 2
Related
From http://en.cppreference.com/w/cpp/container/unordered_map/unordered_map, unordered_map can use lambda functions for hashing function. It is also answered in the following: How to use lambda function as hash function in unordered_map?
My question is about hashing a struct which includes a container, say a vector. Since cpprefence has the following code example of
#include <algorithm>
#include <cassert>
#include <string>
#include <unordered_set>
#include <vector>
#include <unordered_map>
using std::hash;
using std::string;
using std::unordered_set;
using std::vector;
int main(int argc, char* argv[]) {
struct Goo {int val; };
auto hash = [](const Goo &g){ return std::hash<int>{}(g.val); };
auto comp = [](const Goo &l, const Goo &r){ return l.val == r.val; };
std::unordered_map<Goo, double, decltype(hash), decltype(comp)> m8(10, hash, comp);
return 0;
}
I have modified it so that it tries to use vector<int> in the Goo.
#include <algorithm>
#include <cassert>
#include <string>
#include <unordered_set>
#include <vector>
#include <unordered_map>
using std::hash;
using std::string;
using std::unordered_set;
using std::vector;
int main() {
using vint = std::vector<int>;
struct Goo { vint v; };
auto hash = [](const Goo &g){
std::size_t hash_value = 0;
for (const int& i : g.v) {
hash_value ^= std::hash<int>{}(i);
}
return hash_value;
};
auto comp = [](const Goo &l, const Goo &r){
return unordered_set<int>(l.v.begin(), l.v.end()) ==
unordered_set<int>(r.v.begin(), r.v.end());
};
vint here;
std::unordered_map<Goo, double, decltype(hash), decltype(comp)>
m8(here,0, hash, comp);
return 0;
}
This code doesn't compile. The compiler complains about not no matching function for call to ‘std::unordered_map<main(int, char**)::Goo. The number of arguments seems to be not the issue, but something must be working not correctly. I would greatly appreciate your guidance.
I am using g++ -std=c++17 by the way.
I think that you didn't understand the example. This line:
std::unordered_map<Goo, double, decltype(hash), decltype(comp)> m8(10, hash, comp);
is responsible for creating unordered_map with at least 10 buckets and provided hash and comp functions. It does not create any unordered_map with 10 elements. Therefore, your code should look like this:
using vint = std::vector<int>;
struct Goo { vint v; };
auto hash = [](const Goo &g){
std::size_t hash_value = 0;
for (const int& i : g.v) {
hash_value ^= std::hash<int>{}(i);
}
return hash_value;
};
auto comp = [](const Goo &l, const Goo &r){
return std::unordered_set<int>(l.v.begin(), l.v.end()) ==
std::unordered_set<int>(r.v.begin(), r.v.end());
};
std::unordered_map<Goo, double, decltype(hash), decltype(comp)>
m8(10, hash, comp);
unordered_map simply does not have any constructor that will mach this:
std::unordered_map<Goo, double, decltype(hash), decltype(comp)>
m8(here, 0, hash, comp);
I suggest using the composable hashing infrastructure from N3980 Types Don't Know #. It also saves you from error-prone manual hash combining.
An example of hashing a structure with two members, one of which is a vector:
// Hashing infrastructure begin.
class fnv1a
{
std::size_t state_ = 14695981039346656037u;
public:
using result_type = std::size_t;
void operator()(void const* key, std::size_t len) noexcept {
unsigned char const* p = static_cast<unsigned char const*>(key);
unsigned char const* const e = p + len;
for (; p < e; ++p)
state_ = (state_ ^ *p) * 1099511628211u;
}
explicit operator result_type() noexcept {
return state_;
}
};
template<class HashAlgorithm>
struct uhash
{
using result_type = typename HashAlgorithm::result_type;
template <class T>
result_type operator()(T const& t) const noexcept {
HashAlgorithm h;
hash_append(h, t);
return static_cast<result_type>(h);
}
};
template<class HashAlgorithm, class T>
typename std::enable_if<std::is_integral<T>::value>::type
inline hash_append(HashAlgorithm& h, T const& t) noexcept {
h(&t, sizeof t);
}
template<class HashAlgorithm, class T, class... Args>
void hash_append(HashAlgorithm& h, std::vector<T, Args...> const& v) noexcept {
for(auto const& t : v)
hash_append(h, t);
hash_append(h, v.size());
}
template<class HashAlgorithm, class T, class... Args>
void hash_append(HashAlgorithm& h, std::unordered_map<T, Args...> const& v) noexcept {
for(auto const& t : v)
hash_append(h, t);
hash_append(h, v.size());
}
// Hashing infrastructure end
struct Goo
{
std::vector<int> a;
int b;
template<class HashAlgorithm>
friend void hash_append(HashAlgorithm& h, Goo const& v) noexcept {
hash_append(h, v.a);
hash_append(h, v.b);
}
bool operator==(Goo const& other) const {
return a == other.a && b == other.b;
}
};
int main() {
std::unordered_map<Goo, double, uhash<fnv1a>> m;
m[Goo{{1,2,3}, 1}] = 1;
}
Is it possible to convert a vector of one type to another implicitly?
i.e some way to make this code work (obviously this is a simplified problem of what I am trying to do)
std::vector<int> intVec;
intVec.push_back(1);
std::vector<double> doubleVec = intVec;
std::vector<double> doubleVec2;
doubleVec2 = intVec;
No, there is no conversion (implicit or otherwise) between different vector types.
You could initialise it from an iterator range:
std::vector<double> doubleVec(intVec.begin(), intVec.end());
perhaps wrapping this in a function:
template <typename To, typename From>
To container_cast(From && from) {
using std::begin; using std::end; // Koenig lookup enabled
return To(begin(from), end(from));
}
auto doubleVec = container_cast<std::vector<double>>(intVec);
template<class T, class A=std::allocator<T>>
struct magic_vector:std::vector<T,A> {
using base=std::vector<T,A>;
using base::base;
magic_vector(magic_vector const&)=default;
magic_vector(magic_vector &&)=default;
magic_vector& operator=(magic_vector const&)=default;
magic_vector& operator=(magic_vector &&)=default;
magic_vector()=default;
template<class U, class B,
class=typename std::enable_if<std::is_convertible<U,T>::value>::type
>
magic_vector( magic_vector<U,B> const& o ):
base( o.begin(), o.end() )
{}
template<class U, class B,
class=typename std::enable_if<
std::is_convertible<U,T>::value
&& noexcept( T(std::declval<U&&>()) )
>::type
>
magic_vector( magic_vector<U,B>&& o ):
base(
std::make_move_iterator(o.begin()),
std::make_move_iterator(o.end())
)
{}
};
magic_vectors are vectors that auto convert from other magic_vectors.
If you have a pointer to a magic_vector that you convert into a pointer to vector, then delete it as a vector, the result is undefined behavior. (However in practice, there will be no harm in every C++ implementation I have checked). This is, however, a strange way to act with vectors.
Replace use of vector with magic_vector. So long as you don't have specializations on the exact type of a container in your code, it should be a drop-in replacement, except now it will auto-convert between them.
Work could be done to have magic_vectors auto-convert with vectors instead of just with magic_vectors.
One way is to create a conversion function. It allows you to express intent at the call site:
#include <iostream>
#include <vector>
template<class To, class From, class Allocator>
std::vector<To, typename Allocator::template rebind<To>::other>
implicit_convert(const std::vector<From, Allocator>& vf)
{
return { std::begin(vf), std::end(vf) };
}
template<class To, class ToA, class From, class FromA>
void implicit_overwrite(std::vector<To, ToA>& to, const std::vector<From, FromA>& from)
{
to.clear();
std::copy(begin(from), end(from), back_inserter(to));
}
int main(int argc, const char * argv[]) {
using namespace std;
std::vector<int> vi { 1, 2 , 3 };
auto vd = implicit_convert<double>(vi);
cout << "after conversion\n";
for (const auto& i : vd) {
cout << i << endl;
}
vi.push_back(4);
implicit_overwrite(vd, vi);
cout << "after copy\n";
for (const auto& i : vd) {
cout << i << endl;
}
return 0;
}
expected output:
after conversion
1
2
3
after copy
1
2
3
4
you could go for something like this (assuming myclass is your class that can be constructed from a std::pair):
#include <iostream>
#include <vector>
#include <utility>
using std::cout;
using std::endl;
class myclass
{
public:
myclass(const std::pair<int, int>& p): first_(p.first), second_(p.second) {}
int first() {return first_;}
int second() {return second_;}
private:
int first_;
int second_;
};
template <class T>
class myvector : public std::vector<T>
{
using base = std::vector<T>;
using base::base;
};
template<>
class myvector<myclass> : public std::vector<myclass>
{
public:
myvector(const std::vector<std::pair<int, int>>& vp):
std::vector<myclass>(vp.begin(), vp.end()) {}
};
int main()
{
std::vector<std::pair<int, int>> vp {{12,3}, {1, 7}};
myvector<myclass> mm = vp;
cout<<mm[0].first(); //prints 12
}
You inherit myvector from std::vector and then you specialize it for myclass. Alternatively you could define myvector in a namespace and access it as mynamespace::vector<myclass>
My question is what is the type for *it, if it is of the type of std::map<std::string, int>::iterator
As a follow up to that question, if I would like to use accumulate to calculate all the map values, how could I do? Thanks.
It's a reference to an std::pair<const KeyT, ValueT> (where KeyT and ValueT are the key and value parameters of the map). You may write some kind of iterator wrapper to wrap map iterators, make them return just the value and then use std::accumulate:
template<typename ItT>
struct SecondIterator
{
ItT it;
SecondIterator(const ItT &it) : it(it) {}
SecondIterator &operator++()
{
++it;
return *this;
}
SecondIterator operator++(int)
{
SecondIterator t=*this;
++(*this);
return t;
}
SecondIterator &operator--()
{
--it;
return *this;
}
SecondIterator operator--(int)
{
SecondIterator t=*this;
--(*this);
return t;
}
typename ItT::value_type::second_type &operator*()
{
return it->second;
}
bool operator==(const SecondIterator &other)
{
return it==other.it;
}
bool operator!=(const SecondIterator &other)
{
return it!=other.it;
}
};
(probably I forgot some typename here and there, but you got the idea)
but if you ask me it's definitely not worth the effort.
If you want to accumulate the mapped_type of a std::map, perhaps the following helper classes will be of interest:
#include <functional>
#include <numeric>
#include <utility>
#ifndef USE_CXX11
#if (__cplusplus >= 201100) || (_MSC_VER >= 1800)
#define USE_CXX11 1
#endif
#endif
#if USE_CXX11
/*
map_value_accumulator - helper class that allows iterators of std::map
to be used with std::accumulate
*/
template <typename T, typename Op = std::plus<typename T::mapped_type> >
class map_value_accumulator
{
public:
typedef typename T::value_type pair_type;
typedef typename T::mapped_type value_type;
value_type operator()( value_type acc, pair_type const& p) const {
return op_( acc, p.second);
}
map_value_accumulator() : op_(Op()) {};
map_value_accumulator(Op&& op) : op_(op) {};
private:
Op op_;
};
/*
make_map_value_accumulator() - function that uses argument deduction to
help create map_value_accumulator objects
*/
// make_map_value_accumulator() that returns a user-specified operation
// the operation defaults to std::plus<> is not specified
template <typename T, typename Op = std::plus<typename T::mapped_type> >
map_value_accumulator< T, Op>
make_map_value_accumulator( T const& m, Op&& op = Op())
{
return map_value_accumulator< T, Op>(std::forward<Op>(op));
}
#else
/*
map_value_accumulator - helper class that allows iterators of std::map
to be used with std::accumulate
*/
template <typename T, typename Op = std::plus<typename T::mapped_type> >
class map_value_accumulator
{
public:
typedef typename T::value_type pair_type;
typedef typename T::mapped_type value_type;
typedef std::plus<typename T::mapped_type> default_operator_type;
value_type operator()( value_type acc, pair_type const& p) const {
return op_( acc, p.second);
}
map_value_accumulator() : op_(default_operator_type()) {};
map_value_accumulator(Op op) : op_(op) {};
private:
Op op_;
};
/*
make_map_value_accumulator() - function that uses argument deduction to
help create map_value_accumulator objects
*/
template <typename T, typename Op>
map_value_accumulator< T, Op>
make_map_value_accumulator( T const& m, Op const& op)
{
return map_value_accumulator< T, Op>(op);
}
template <typename T>
map_value_accumulator< T, std::plus<typename T::mapped_type> >
make_map_value_accumulator( T const& m)
{
typedef std::plus<typename T::mapped_type> default_operator_type;
return map_value_accumulator< T, default_operator_type>();
}
#endif /* USE_CXX11 */
#include <iostream>
#include <ostream>
#include <map>
int main()
{
std::map<char, int> m;
m.insert(std::make_pair('a', 1));
m.insert(std::make_pair('z', 26));
m.insert(std::make_pair('c', 3));
m.insert(std::make_pair('b', 2));
m.insert(std::make_pair('?', -2));
using std::cout;
using std::endl;
// directly create the map_value_accumulator functor (defaults to std::plus)
cout << accumulate(m.begin(), m.end(), 0, map_value_accumulator<std::map<char,int> >()) << endl;
// create a map_value_accumulator deduced from the user's map type (default to std::plus)
cout << accumulate(m.begin(), m.end(), 0, make_map_value_accumulator(m)) << endl;
// create a map_value_accumulator deduced from the user's map type and specifying an operation functor
cout << accumulate(m.begin(), m.end(), 1, make_map_value_accumulator(m, std::multiplies<int>())) << endl;
#if USE_CXX11
cout << "accumulate with a lambda: ";
// create a map_value_accumulator deduced from the user's map type and specifying a lambda for the operation
// (will perform a sum of squares)
cout << accumulate(m.begin(), m.end(), 0, make_map_value_accumulator(m, [](int x, int y){ return x + y * y; })) << endl;
#endif
return 0;
}
Note: I've updated the example. The first example would not work with lambdas and didn't work with MS compilers older than VS 2013. The new example has some conditional compilation that has a C++11 implementation (that supports lambdas) and a non-C++11 variant that works with VS 2003 and later and presumably any reasonable version of GCC.
I'm trying to create a class where a user can store different type of data in maps. I've created a map for bool, int and std::string and created template functions so that I don't have to rewrite the get and set functions for each type.
Here's a minmal version of my code:
#include <map>
#include <string>
#include <stdexcept>
#include <iostream>
class Options {
public:
template<class T>
void Set(const std::string& name, const T& value) {
GetMap<T>()[name] = value;
}
template<class T>
T Get(const std::string& name) {
auto it = GetMap<T>().find(name);
if(it == GetMap<T>().end()) {
throw std::runtime_error(name + " not found");
}
return it->second;
}
private:
std::map<std::string, int> ints_;
std::map<std::string, std::string> strings_;
std::map<std::string, bool> bools_;
template<class T>
std::map<std::string, T>& GetMap();
template<bool>
std::map<std::string, bool>& GetMap() {
return bools_;
}
template<std::string> // error
std::map<std::string, std::string>& GetMap() {
return strings_;
}
template<int>
std::map<std::string, int>& GetMap() {
return ints_;
}
};
int main() {
Options o;
o.Set("test", 1234);
o.Set<std::string>("test2", "Hello World!");
std::cout << o.Get<int>("test") << std::endl
<< o.Get<std::string>("test2") << std::endl;
}
I'm getting the following error:
error: 'struct std::basic_string<char>' is not a valid type for a template constant parameter
But why?
If I understand correctly, you're trying to specialise the function template GetMap(). But your syntax is incorrect; you probably want:
template<class T>
std::map<std::string, T>& GetMap();
template<>
std::map<std::string, bool>& GetMap<bool>() {
return bools_;
}
and so on.
Two points:
The specialization should be outside the class (important), otherwise it will not compile
The correct syntax of the specialization is as follows:
//outside the class definition
template<>
std::map<std::string, bool>& Options::GetMap<bool>() {
//^^^^^^^^^ dont forget this!
return bools_;
}
template<>
std::map<std::string, std::string>& Options::GetMap<std::string>() {
//^^^^^^^^^ dont forget this!
return strings_;
}
template<>
std::map<std::string, int>& Options::GetMap<int>() {
//^^^^^^^^^ dont forget this!
return ints_;
}
I am trying to write an iterator class which returns a getter function return value when it is dereferenced. The code works fine, my only problem is that I would like to write the member_ptr_functor using only one template parameter and not 3, since I am supposed to be able to deduce the types of the argument and return value from the member function type. I think the problematic one is the argument type, I tried using boost::remove_ptr&, but I couldn't compile it.
#include <iostream>
#include <vector>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/iterator/indirect_iterator.hpp>
using namespace boost;
using namespace std;
class CTest
{
private:
int m_x;
public:
CTest(int x) : m_x(x)
{
}
const int& GetX() const
{
return m_x;
}
};
template<typename MemFunType, typename ArgumentType, typename ResultType>
class member_ptr_functor : public unary_function<ArgumentType, ResultType>
{
private:
MemFunType m_MemFun;
public:
typedef ArgumentType argument_type;
typedef ResultType result_type;
member_ptr_functor(MemFunType MemFun) : m_MemFun(MemFun)
{
}
result_type operator() (argument_type arg) const
{
return m_MemFun(&arg);
}
};
template<typename MemFunType, typename ArgumentType, typename ResultType>
member_ptr_functor<MemFunType, ArgumentType, ResultType> make_member_ptr_functor(MemFunType MemFun)
{
return member_ptr_functor<MemFunType, ArgumentType, ResultType>(MemFun);
}
class CPrintFunctor : public unary_function<int, void>
{
public:
void operator() (const int n) const
{
cout << n << endl;
}
};
int main()
{
typedef vector<CTest> Container_t;
Container_t v;
v.push_back(CTest(1));
CPrintFunctor PF;
Container_t::const_iterator itStart = v.begin();
Container_t::const_iterator itEnd = v.end();
typedef member_ptr_functor<const_mem_fun_t<const int&, CTest> , CTest, const int&> member_ptr_functor_t;
member_ptr_functor_t MemberPtrFunctor = member_ptr_functor_t(mem_fun(&CTest::GetX));
typedef transform_iterator<member_ptr_functor_t, Container_t::const_iterator, const int&, const int> transform_iterator_t;
transform_iterator_t itTransformStart = make_transform_iterator(itStart, MemberPtrFunctor);
transform_iterator_t itTransformEnd = make_transform_iterator(itEnd, MemberPtrFunctor);
for_each(itTransformStart, itTransformEnd, PF);
return 0;
}
Hagai.
This does not answer your question directly but rather suggests alternative approach.
You are already using Boost, so why do you not take it one step further, use Boost.Range:
#include <boost/functional.hpp>
#include <boost/range.hpp>
#include <boost/range/algorithm/for_each.hpp>
#include <boost/range/adaptor/transformed.hpp>
// ...
int main ()
{
// ...
boost::range::for_each (
boost::adaptors::transform (v, boost::mem_fun_ref (&CTest::GetX)),
PF);
}
This lets you write the functionality that you want without having to define own functors and without using too many typedefs.