Related
I am creating a function which should take as input iterators to vector
for example:
vector<int> a;
foo(a.begin(),a.end())
The vector can hold any type.
Now the simple way to do this is using templates
template <typename Iterator>
void foo(Iterator first, Iterator last) {
for (Iterator it = first; it!=last; ++it) {
cout << *it;
}
}
I want to know if there is a way to achieve the same functionality without using templates. Since using Templates would force me to include these functions in Header file of a public API which I don't want to. So I wanted to know is there an alternate way to access the iterators without using Templates.
There are ways not to include the implementation in header files but they are not clean to implement (for instance you should know in advance the instantiations). Read here for more info about this issue:
Why can’t I separate the definition of my templates class from its declaration and put it inside a .cpp file?
How can I avoid linker errors with my template functions?
For instance in:
foo.h
#ifndef HI_
#define HI_
template<class Iterator>
void foo(Iterator first, Iterator last);
#endif
foo.cpp
#include "stack.h"
using namespace std;
template<class Iterator>
void foo(Iterator first, Iterator last) {
for (Iterator it = first; it != last; ++it) {
cout << *it << " ";
}
}
template
void foo( std::vector<int>::iterator first, std::vector<int>::iterator last);
template
void foo( std::vector<double>::iterator first, std::vector<double>::iterator last);
Now you can use foo function only for double and int. Other types won't link.
Hope this helps.
This is a long answer. The short answer is "type erasure"; go learn about it.
The long answer is two answers. First I cover "do you just want to be able to iterate over contiguous ints?". Then you want span. This is a really simple form of type erasure that forgets what the exact container is you are working on so long as it is contiguous and over T.
The second answer is if you actually need to deal with multiple types (not just int) and multiple kinds of containers (not just contiguous ones).
The two answers are separated by a line.
The span concept (see gsl::span) is designed for pretty much this reason. It itself is a template (over the type you are working with), but it will be a concrete instance of a template in most interfaces.
Here is a toy version of it:
template<class T>
struct span_t {
T* b = 0;
T* e = 0;
T* begin() const { return b; }
T* end() const { return e; }
span_t(span_t const&)=default;
span_t& operator=(span_t const&)=default;
span_t()=default;
span_t( T* s, T* f ):b(s),e(f) {}
span_t( T* s, std::size_t l):span_t(s, s+l){}
template<std::size_t N>
span_t( T(&arr)[N] ):span_t(arr, N) {}
std::size_t size() const { return end()-begin(); }
bool empty() const { return begin()==end(); }
T& front() const { return *begin(); }
T& back() const { return *(std::prev(end()); }
T* data() const { return begin(); }
span_t without_front( std::size_t N=1 ) const {
return {std::next( begin(), (std::min)(N, size()) ), end()};
}
span_t without_back( std::size_t N=1 ) const {
return {begin(), std::prev(end(), (std::min)(N, size()) )};
}
};
we can augment it with conversion operators
namespace details {
template<template<class...>class Z, class, class...Ts>
struct can_apply:std::false_type{};
template<class...>using void_t=void;
template<template<class...>class Z, class...Ts>
struct can_apply<Z, void_t<Z<Ts...>>, Ts...>:std::true_type{};
}
template<template<class...>class Z, class...Ts>
using can_apply = details::can_apply<Z,void,Ts...>;
template<class C>
using dot_data_r = decltype( std::declval<C>().data() );
template<class C>
using dot_size_r = decltype( std::declval<C>().size() );
template<class C>
using can_dot_data = can_apply< dot_data_r, C >;
template<class C>
using can_dot_size = can_apply< dot_size_r, C >;
can_dot_data detects via SFINAE if .data() is valid to do on an object of type C.
Now we add a constructor:
template<class T,
std::enable_if_t<
can_dot_data<T&>{}
&& can_dot_size<T&>{}
&& !std::is_same<std::decay_t<T>, span_t>{}
, int
> =0
>
span_t( T&& t ): span_t( t.data(), t.size() ) {}
which covers std::vector and std::string and std::array.
Your function now looks like:
void foo(span_t<int> s) {
for (auto&& e:s)
std::cout << s;
}
}
with use:
std::vector<int> a;
foo(a);
now, this only works for contiguous containers of a specific type.
Suppose this is not what you want. Maybe you do need to solve this for a myriad of types, and you don't want to expose everything in the header.
Then what you need to do is known as type erasure.
You need to work out what minimal set of operations you need from the provided types. Then you need to write wrappers that "type erase" these operations down to "typeless" operations.
This goes in the header, or in another helper header.
In the interface of the function, or in a header intermediate helper, you take the incoming types and do the type erasure, then pass the type-erased types into the "real" implementation.
An example of type erasure is std::function. It takes almost anything that can be invoked with a fixed signature, and turns it into a single type-erased type. Everything except how to copy, destroy and invoke an instance of the type is "forgotten" or erased.
For your case:
template <typename Iterator>
void foo(Iterator first, Iterator last) {
for (Iterator it = first; it!=last; ++it) {
cout << *it;
}
}
I see two things that need to be erased down to; iteration, and printing.
struct printable_view_t {
void const* data = 0;
void(*print_f)(std::ostream& os, void const*) = 0;
explicit operator bool()const{return data;}
printable_view_t() = default;
printable_view_t(printable_view_t const&) = default;
template<class T,
std::enable_if_t<!std::is_same<T, printable_view_t>{}, int> =0
>
printable_view_t( T const& t ):
data( std::addressof(t) ),
print_f([](std::ostream& os, void const* pv){
auto* pt = static_cast<T const*>(pv);
os << *pt;
})
{}
std::ostream& operator()(std::ostream& os)const {
print_f(os, data);
return os;
}
friend std::ostream& operator<<(std::ostream& os, printable_view_t p) {
return p(os);
}
};
printable_view_t is an example of type-erasing "I can be printed".
void bar( printable_view_t p ) {
std::cout << p;
}
void test_bar() {
bar(7);
bar(3.14);
bar(std::string("hello world"));
}
The next thing we'd have to do is type erase iteration. This is harder, because we want to type erase iteration over iterating over a printable_view_t type.
Type erasing foreach is a tad easier, and often more efficient.
template<class View>
struct foreach_view_t {
void* data = 0;
void(*func)( std::function<void(View)>, void* ) = 0;
explicit operator bool()const{return data;}
foreach_view_t() = default;
foreach_view_t(foreach_view_t const&) = default;
template<class T,
std::enable_if_t<!std::is_same<std::decay_t<T>, foreach_view_t>{}, int> =0
>
foreach_view_t( T&& t ):
data( const_cast<std::decay_t<T>*>(std::addressof(t)) ),
func([](std::function<void(View)> f, void* pv){
auto* pt = static_cast<std::remove_reference_t<T>*>(pv);
for (auto&& e : *pt)
f(decltype(e)(e));
})
{}
void operator()(std::function<void(View)> f)const{
func(f, data);
}
};
we then daisy chain these together
void foo(foreach_view_t<printable_view_t> x) {
x([](auto p){ std::cout << p; });
}
test code:
std::vector<int> a{1,2,3};
foo(a);
Now much of the header code was "hoisted" into the type erasure types instead of a function template body. But careful choice of the points of type erasure can let you keep what you need from the types precise and narrow, and the logic of how you use those operations private.
As an example, the above code doesn't care where you are printing it to; std::cout was not part of the type erasure.
Live example.
I want to know if there is a way to achieve the same functionality without using templates. [...] I wanted to know is there an alternate way to access the iterators without using Templates.
Yes, if you use C++14, but...
Since using Templates would force me to include these functions in Header file of a public API which I don't want to.
... isn't a useful way for you because it's equivalent to use templates and you have to put it in the header file.
In C++14 you can use a lambda function with auto parameters.
auto foo = [](auto first, auto last)
{ for (auto it = first ; it != last; ++it ) std::cout << *it; };
The autos aren't template (from a formal point of view) but are equivalent and you can't declare foo in the header and develop it in a cpp file.
guess I have a
class C1 : public B { /*...*/ };
class C2 : public B { /*...*/ };
std::map<std::string, C1> myMap;
std::vector<C2> myVector;
Is there a way (and what would be the syntax) to call a function foo that…
just needs to process the functionalities of B
just needs to process them on all elements of map and vector without caring how they are organized?
std::vector and std::map are both std::_Container_base's but i have no clue how to write the syntax for (pseudocode):
void foo(std::_Container_base-of-Bs)
EDIT: it's _Container_base, not _Tee
The C++ way is to use templates and iterators.
template <typename ForwardIterator>
void process_bs(ForwardIterator first, ForwardIterator last) {
std::for_each(first, last, [](B& b) {
// do something to b here
});
}
For vector, list, deque and set, you can trivially call this using begin and end:
process_bs(v.begin(), v.end());
For map, the element type is pair<const Key, Value>, so you have to adapt the iterators. You can use this with Boost.Range, for example:
#include <boost/range/adaptor/map.hpp>
auto values = m | boost::adaptors::map_values;
process_bs(values.begin(), values.end());
EDIT: The below is a survey on the workarounds, whereas the actual question is not answered therein. So here is the answer: I don't know whether one can process std::_Container_base without knowing if it is a map or a vector.
I couldn't find anything reasonable on the web regarding std::_Container_base, and particularly no C++ standard things, so I would guess it stems from a specific compiler implementation.
vector and map are completely different storage schemes. I suggest you to not use them generically in the same context. That is, from the first you could write a function template
template<typename T> foo(T&& t) { /* takes a vector and a map */ }
but at least when you access operator[], they'll behave differently. That would be unintuitive and error-prone.
However, this doesn't mean you cannot combine the two approaches -- and abstract on size(), operator[](int) and possibly other things like some insertion mechanism.
For example, in some recent code of mine, I have vector-storage scheme (which uses std::vector under the hood), as well as a piecewise constant vector (which uses a std::map). If you want to do this, you can derive those two from a common base class
template<typename T>
struct ContainerBase
{
virtual int size() const = 0;
virtual T operator[](int) const = 0;
virtual void insert(int, T) = 0; //if required
};
and then set up the required functionality in the derived classes Vector and Map.
template<typename T>
struct Vector
{
virtual T operator[](int i) const { return _v[i]; }
virtual T size() const { return _v.size(); }
// ... insert and so on
std::vector<T> _v;
};
template<typename T>
struct Map
{
virtual T operator[](int i) const
{
return *std::lower_bound(i); //add further checks if nothing is found
}
virtual T size() const { return _v.rbegin()->first; // return highest index }
// ... insert and so on
std::map<int, T> _v;
};
The Map implementation is just a sketch. You should choose some reasonable behaviour for it.
With this, it is easy to set up a function foo(ContainerBase&) which works for both Vector and Map.
To use transparently B subclasses into the foo function, you can do this way:
#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <utility>
struct B{
int b_member;
};
class C1 : public B { /*...*/ };
class C2 : public B { /*...*/ };
std::map<std::string, C1> myMap;
std::vector<C2> myVector;
// all the magic is into get_B specializations
template<typename E, typename std::enable_if<std::is_base_of<B, E>::value>::type* a = nullptr>
B& get_B(E& elem)
{
return elem;
}
template<typename E, typename std::enable_if<std::is_base_of<B, typename E::second_type>::value>::type* a = nullptr>
B& get_B(E& elem)
{
return elem.second;
}
// foo can call get_B to hide implementation details of the container
template<typename T>
void foo( T& container)
{
for(auto& elem : container)
{
std::cout << get_B(elem).b_member << '\n';
}
}
int main()
{
myVector.resize(10);
myMap["one"] = {};
foo(myMap);
foo(myVector);
}
Thanks to SFINAE, foo uses the correct specialization of get_B to get a reference to the B subclass you want to process.
I have trouble describing my problem so I'll give an example:
I have a class description that has a couple of variables in it, for example:
class A{
float a, b, c, d;
}
Now, I maintain a vector<A> that contains many of these classes. What I need to do very very often is to find the object inside this vector that satisfies that one of it's parameters is maximal w.r.t to the others. i.e code looks something like:
int maxi=-1;
float maxa=-1000;
for(int i=0;i<vec.size();i++){
res= vec[i].a;
if(res > maxa) {
maxa= res;
maxi=i;
}
}
return vec[maxi];
However, sometimes I need to find class with maximal a, sometimes with maximal b, sometimes the class with maximal 0.8*a + 0.2*b, sometimes I want a maximal a*VAR + b, where VAR is some variable that is assigned in front, etc. In other words, I need to evaluate an expression for every class, and take the max. I find myself copy-pasting this everywhere, and only changing the single line that defines res.
Is there some nice way to avoid this insanity in C++? What's the neatest way to handle this?
Thank you!
I know this thread is old, but i find it quite useful to implement a powerful argmax function in C++.
However, as far as i can see, all the given examples above rely on std::max_element, which does comparison between the elements (either using a functor or by calling the operator<). this can be slow, if the calculation for each element is expensive. It works well for sorting numbers and handling simple classes, but what if the functor is much more complex? Maybe calculating a heuristic value of a chess position or something else that generate a huge tree etc.
A real argmax, as the thread starter mentioned, would only calculate its arg once, then save it to be compared with the others.
EDIT: Ok i got annoyed and had too much free time, so i created one < C++11 and one C++11 version with r-value references, first the C++11 version:
#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
template<typename IteratorT, typename HeuristicFunctorT>
IteratorT argmax(IteratorT && it, const IteratorT & end, const HeuristicFunctorT & functor) {
IteratorT best(it++);
typename HeuristicFunctorT::result_type best_value(functor(*best));
for(; it != end; ++it) {
typename HeuristicFunctorT::result_type value(functor(*it));
if (value > best_value) {
best_value = value;
best = it;
}
}
return best;
}
template<typename IteratorT, typename HeuristicFunctorT>
inline IteratorT argmax(const IteratorT & begin, const IteratorT & end, const HeuristicFunctorT & functor) {
return argmax(IteratorT(begin), end, functor);
}
class IntPairFunctor : public std::unary_function< std::pair<int, int>, int > {
public:
int operator() (const std::pair<int, int> & v) const {
return v.first + v.second;
}
};
std::pair<int, int> rand_pair() {
return std::make_pair(rand(), rand());
}
int main(int argc, const char **argv) {
srand(time(NULL));
std::vector< std::pair<int, int> > ints;
std::generate_n(std::back_insert_iterator< std::vector< std::pair<int, int> > >(ints), 1000, rand_pair);
std::vector< std::pair<int, int> >::iterator m (argmax(ints.begin(), ints.end(), IntPairFunctor()));
std::cout << std::endl << "argmax: " << *m << std::endl;
}
The non C++11 version is much simpler, only the template:
template<typename IteratorT, typename HeuristicFunctorT>
IteratorT argmax(IteratorT it, const IteratorT & end, const HeuristicFunctorT & functor) {
IteratorT best(it++);
typename HeuristicFunctorT::result_type best_value(functor(*best));
for(; it != end; ++it) {
typename HeuristicFunctorT::result_type value(functor(*it));
if (value > best_value) {
best_value = value;
best = it;
}
}
return best;
}
Note that neither version requires any template arguments, the only requirement is that the heuristic implements the unary_function class
template <typename F>
struct CompareBy
{
bool operator()(const typename F::argument_type& x,
const typename F::argument_type& y)
{ return f(x) < f(y); }
CompareBy(const F& f) : f(f) {}
private:
F f;
};
template <typename T, typename U>
struct Member : std::unary_function<U, T>
{
Member(T U::*ptr) : ptr(ptr) {}
const T& operator()(const U& x) { return x.*ptr; }
private:
T U::*ptr;
};
template <typename F>
CompareBy<F> by(const F& f) { return CompareBy<F>(f); }
template <typename T, typename U>
Member<T, U> mem_ptr(T U::*ptr) { return Member<T, U>(ptr); }
You need to include <functional> for this to work. Now use, from header <algorithm>
std::max_element(v.begin(), v.end(), by(mem_ptr(&A::a)));
or
double combination(A x) { return 0.2 * x.a + 0.8 * x.b; }
and
std::max_element(v.begin(), v.end(), by(std::fun_ptr(combination)));
or even
struct combination : std::unary_function<A, double>
{
combination(double x, double y) : x(x), y(y) {}
double operator()(const A& u) { return x * u.a + y * u.b; }
private:
double x, y;
};
with
std::max_element(v.begin(), v.end(), by(combination(0.2, 0.8)));
to compare by a member or by linear combinations of a and b members. I split the comparer in two because the mem_ptr thing is damn useful and worth being reused. The return value of std::max_element is an iterator to the maximum value. You can dereference it to get the max element, or you can use std::distance(v.begin(), i) to find the corresponding index (include <iterator> first).
See http://codepad.org/XQTx0vql for the complete code.
This is what functors and STL are made for:
// A class whose objects perform custom comparisons
class my_comparator
{
public:
explicit my_comparator(float c1, float c2) : c1(c1), c2(c2) {}
// std::max_element calls this on pairs of elements
bool operator() (const A &x, const A &y) const
{
return (x.a*c1 + x.b*c2) < (y.a*c1 + y.b*c2);
}
private:
const float c1, c2;
};
// Returns the "max" element in vec
*std::max_element(vec.begin(), vec.end(), my_comparator(0.8,0.2));
Is the expression always linear? You could pass in an array of four coefficients. If you need to support arbitrary expressions, you'll need a functor, but if it's just an affine combination of the four fields then there's no need for all that complexity.
You can use the std::max_element algorithm with a custom comparator.
It's easy to write the comparator if your compiler supports lambda expressions.
If it doesn't, you can write a custom comparator functor. For the simple case of just comparing a single member, you can write a generic "member comparator" function object, which would look something like this:
template <typename MemberPointer>
struct member_comparator
{
MemberPointer p_;
member_comparator(MemberPointer p) : p_(p) { }
template <typename T>
bool operator()(const T& lhs, const T& rhs) const
{
return lhs.*p_ < rhs.*p_;
}
};
template <typename MemberPointer>
member_comparator<MemberPointer> make_member_comparator(MemberPointer p)
{
return member_comparator<MemberPointer>(p);
}
used as:
// returns an iterator to the element that has the maximum 'd' member:
std::max_element(v.begin(), v.end(), make_member_comparator(&A::d));
You could use the std::max_element STL algorithm providing a custom comparison predicate each time.
With C++0x you can even use a lambda function for it for maximum conciseness:
auto maxElement=*std::max_element(vector.begin(), vector.end(), [](const A& Left, const A& Right) {
return (0.8*Left.a + 0.2*Left.b)<(0.8*Right.a + 0.2*Right.b);
});
Sample of using max_element/min_element with custom functor
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
struct A{
float a, b, c, d;
};
struct CompareA {
bool operator()(A const & Left, A const & Right) const {
return Left.a < Right.a;
}
};
int main() {
vector<A> vec;
vec.resize(3);
vec[0].a = 1;
vec[1].a = 2;
vec[2].a = 1.5;
vector<A>::iterator it = std::max_element(vec.begin(), vec.end(), CompareA());
cout << "Largest A: " << it->a << endl;
it = std::min_element(vec.begin(), vec.end(), CompareA());
cout << "Smallest A: " << it->a << endl;
}
Edit: I fixed my mistake: I'm using a set and not a vector.
Please consider the following example code:
set<Foo *> set_of_foos;
set_of_foos.insert(new Foo(new Bar("x")));
set_of_foos.insert(new Foo(new Bar("y")));
[...]
// The way a "foo" is found is not important for the example.
bool find_foo(Foo *foo) {
return set_of_foos.end() != set_of_foos.find(foo);
}
Now when I call:
find_foo(new Foo(new Bar("x")));
the function returns false since what I'm looking for can't be found. The reason is obvious to me: The pointers point to different objects since they are allocated both with a new, resulting in different values of the addresses.
But I want to compare the contents of Foo (i.e. "x" in the above example) and not Foo * itself. Using Boost is not an option as well as modifying Foo.
Do I need to loop through each of the Foo * inside set_of_foos or is there a simpler solution? I tried uniquely serializing the contents of each Foo and replace the set<Foo *> with a map<string, Foo *>, but this seems like a very "hacked" solution and not very efficient.
Change your vector to set with your custom comparable function to compare Foo objects.
Should be:
struct ltFoo
{
bool operator()(Foo* f, Foo* s) const
{
return f->value() < s->value();
}
};
set<Foo*, ltFoo> sFoo;
sFoo.insert(new Foo(new Bar("x"));
sFoo.insert(new Foo(new Bar("y"));
if (sFoo.find(new Foo(new Bar("y")) != sFoo.end())
{
//exists
}
else
{
//not exists
}
find_foo(new Foo(new Bar("x"))); does not sound like a good idea - it will most likely (in any scenario) lead to memory leak with that search function.
You could use find_if with a functor:
struct comparator {
Foo* local;
comparator(Foo* local_): local(local_) {}
~comparator() { /* do delete if needed */ }
bool operator()(const Foo* other) { /* compare local with other */ }
};
bool found = vec.end() != std::find_if(vec.begin(), vec.end(), comparator(new Foo(...)));
Do I need to loop through each of the Foo * inside vector_of_foos or is there a simpler solution?
You do need to loop to find what you want, but you can use std::find_if or another "wrapped loop". This is more natural with lambdas in C++0x, but in C++03 I'd just use a regular for loop, possibly wrapped in your own function if you need to do this in more than one place.
Instead of using std::find, use std::find_if and provide your own predicate. This of course relies in you being able to access the member that holds "x" in Foo.
struct FooBar
{
FooBar(Foo* search) : _search(search){}
bool operator(const Foo* ptr)
{
return ptr->{access to member} == _search->{access to member};
}
Foo* _search;
}
vector<Foo*>::iterator it = std::find_if(vec.begin(), vec.end(), FooBar(new Foo(new Bar("x")));
If you can't access the member and you can guarantee that all other members will be the same, you could try a bare memcmp in the above functor rather than "==".
You may consider also using the Boost Ptr container library. It allows having a list of pointers using standard algorithms, find, etc. as if it contained objects, and automatically releasing the memory used by the pointers upon vector deletion.
I had the same question and ended up writing a simple DereferenceCompare class to do the job. I'd be curious to know what others think of this. At the crux of the problem is that the existing answers require the programmer using your set to access it in an unusual way that is prone to leaking memory, i.e. by passing an address of a temporary to std::set::find() or through std::find_if(). What's the point of using a standard container if you're going to access it in a non-standard way? Boost has a good container library that solves this problem. But since transparent comparators were introduced in C++14 you can write a custom comparator that makes std::set::insert() and std::set:find() work as expected without depending on Boost. You could use it as something like std::set< Foo*, DereferenceCompare<Foo, YourFooComparator> > set_of_foos;
#ifndef DereferenceCompare_H
#define DereferenceCompare_H
#include <type_traits>
// Comparator for std containers that dereferences pointer-like arguments.
// Useful for containers of pointers, smart pointers, etc. that require a comparator.
// For example:
// std::set< int*, DereferenceCompare<int> > myset1;
// int myint = 42;
// myset1.insert(&myint);
// myset1.find(&myint) == myset.end(); // false
// myset1.find(myint) == myset.end(); // false
// myset1.find(42) == myset.end(); // false
// myset1.find(24) == myset.end(); // true, 24 is not in the set
// std::set<int*> myset2;
// myset2.insert(&myint); // compiles, but the set will be ordered according to the address of myint rather than its value
// myset2.find(&myint) == myset.end(); // false
// myset2.find(a) == myset.end(); // compilation error
// myset2.find(42) == myset.end(); // compilation error
//
// You can pass a custom comparator as a template argument. It defaults to std::less<T>.
// The type of the custom comparator is accessible as DereferenceCompare::compare.
// For example:
// struct MyStruct { int val; };
// struct MyStructCompare { bool operator() (const MyStruct &lhs, const MyStruct &rhs) const { return lhs.val < rhs.val; } };
// std::set< MyStruct*, DereferenceCompare<MyStruct, MyStructCompare> > myset;
// decltype(myset)::key_compare::compare comparator; // comparator has type MyStructCompare
template< typename T, class Compare = std::less<T> > class DereferenceCompare
{
#if __cplusplus==201402L // C++14
private:
// Less elegant implementation, works with C+=14 and later.
template<typename U> static constexpr auto is_valid_pointer(int) -> decltype(*(std::declval<U>()), bool()) { return std::is_base_of<T, typename std::pointer_traits<U>::element_type>::value || std::is_convertible<typename std::remove_cv<typename std::pointer_traits<U>::element_type>::type, T>::value; }
template<typename U> static constexpr bool is_valid_pointer(...) { return false; }
public:
template<typename U, typename V> typename std::enable_if<is_valid_pointer<U>(0) && is_valid_pointer<V>(0), bool>::type operator() (const U& lhs_ptr, const V& rhs_ptr) const { return _comparator(*lhs_ptr, *rhs_ptr); } // dereference both arguments before comparison
template<typename U, typename V> typename std::enable_if<is_valid_pointer<U>(0) && !is_valid_pointer<V>(0), bool>::type operator() (const U& lhs_ptr, const V& rhs) const { return _comparator(*lhs_ptr, rhs); } // dereference the left hand argument before comparison
template<typename U, typename V> typename std::enable_if<!is_valid_pointer<U>(0) && is_valid_pointer<V>(0), bool>::type operator() (const U& lhs, const V& rhs_ptr) const { return _comparator(lhs, *rhs_ptr); } // dereference the right hand argument before comparison
#elif __cplusplus>201402L // Better implementation, depends on void_t in C++17.
public:
// SFINAE type inherits from std::true_type if its template argument U can be dereferenced, std::false otherwise.
// Its ::value member is true if the type obtained by dereferencing U, i.e. the pointee, is either derived from T or convertible to T.
// Its ::value is false if U cannot be dereferenced, or it the pointee is neither derived from nor convertible to T.
// Example:
// DereferenceCompare<int>::has_dereference; // std::false_type, int cannot be dereferenced
// DereferenceCompare<int>::has_dereference<int>::is_valid_pointee; // false, int cannot be dereferenced
// DereferenceCompare<int>::has_dereference<int*>; // std::true_type, int* can be dereferenced to int
// DereferenceCompare<int>::has_dereference<int*>::is_valid_pointee; // true, dereferencing int* yields int, which is convertible (in fact, the same type as) int
// DereferenceCompare<int>::has_dereference< std::shared_ptr<int> >::is_valid_pointee; // true, the pattern also works with smart pointers
// DereferenceCompare<int>::has_dereference<double*>::is_valid_pointee; // true, double is convertible to int
// struct Base { }; struct Derived : Base { }; DereferenceCompare<Base>::has_dereference<Derived*>::is_valid_pointee; // true, Derived is derived from Base
// DereferenceCompare<int>::has_dereference<Derived*>; // std::true_type, Derived* can be dereferenced to Derived
// DereferenceCompare<int>::has_dereference<Derived*>::is_valid_pointee; // false, cannot convert from Derived to int nor does Derived inherit from int
template< typename, class = std::void_t<> > struct has_dereference : std::false_type { static constexpr bool is_valid_pointee = false; };
template< typename U > struct has_dereference< U, std::void_t<decltype(*(std::declval<U>()))> > : std::true_type { static constexpr bool is_valid_pointee = std::is_base_of<T, typename std::pointer_traits<U>::element_type>::value || std::is_convertible<typename std::remove_cv<typename std::pointer_traits<U>::element_type>::type, T>::value; };
template<typename U, typename V> typename std::enable_if<has_dereference<U>::is_valid_pointee && has_dereference<V>::is_valid_pointee, bool>::type operator() (const U& lhs_ptr, const V& rhs_ptr) const { return _comparator(*lhs_ptr, *rhs_ptr); } // dereference both arguments before comparison
template<typename U, typename V> typename std::enable_if<has_dereference<U>::is_valid_pointee && !has_dereference<V>::is_valid_pointee, bool>::type operator() (const U& lhs_ptr, const V& rhs) const { return _comparator(*lhs_ptr, rhs); } // dereference the left hand argument before comparison
template<typename U, typename V> typename std::enable_if<!has_dereference<U>::is_valid_pointee && has_dereference<V>::is_valid_pointee, bool>::type operator() (const U& lhs, const V& rhs_ptr) const { return _comparator(lhs, *rhs_ptr); } // dereference the right hand argument before comparison
#endif
public:
typedef /* unspecified --> */ int /* <-- unspecified */ is_transparent; // declaration required to enable polymorphic comparisons in std containers
typedef Compare compare; // type of comparator used on dereferenced arguments
private:
Compare _comparator;
};
#endif // DereferenceCompare_H
C++11
If you can make use of C++11 features, then you can also use a lambda expression instead of defining a comparison object,
as shown in the other answers. To make the below example code working, I have defined Bar and Foo from your code as follows:
struct Bar {
Bar(std::string s) : str(s) {}
std::string str;
};
struct Foo {
Foo(Bar* p) : pBar(p) {}
Bar* pBar;
};
If you provide the below lambda expression as key comparison function to the std::set,
then your content (i.e. the strings "x" and "y") is compared instead of the pointers pointing to the content.
Consequently, also the find() works as intended, as shown by the following code:
int main() {
auto comp = [](const Foo* f1, const Foo* f2) { return f1->pBar->str < f2->pBar->str; };
std::set<Foo*, decltype(comp)> set_of_foos(comp);
set_of_foos.emplace(new Foo(new Bar("x")));
set_of_foos.emplace(new Foo(new Bar("y")));
auto it = set_of_foos.find(new Foo(new Bar("x")));
if (it == std::end(set_of_foos))
std::cout << "Element not found!" << std::endl;
else
std::cout << "Element found: " << (*it)->pBar->str << std::endl;
return 0;
}
Output:
Element found: x
Code on Ideone
Note: A std::set only allows unique entries (i.e. keys). Whether entries are unique is decided based on the provided key comparison function.
For the code above this means, that you can only store a single entry with pBar->str == "x", even if Bar or Foo are stored at different adresses.
If you want to store multiple entries with pBar->str == "x" (for example), then you have to use a std::multiset.
Is there a way to specify the default value std::map's operator[] returns when an key does not exist?
While this does not exactly answer the question, I have circumvented the problem with code like this:
struct IntDefaultedToMinusOne
{
int i = -1;
};
std::map<std::string, IntDefaultedToMinusOne > mymap;
No, there isn't. The simplest solution is to write your own free template function to do this. Something like:
#include <string>
#include <map>
using namespace std;
template <typename K, typename V>
V GetWithDef(const std::map <K,V> & m, const K & key, const V & defval ) {
typename std::map<K,V>::const_iterator it = m.find( key );
if ( it == m.end() ) {
return defval;
}
else {
return it->second;
}
}
int main() {
map <string,int> x;
...
int i = GetWithDef( x, string("foo"), 42 );
}
C++11 Update
Purpose: Account for generic associative containers, as well as optional comparator and allocator parameters.
template <template<class,class,class...> class C, typename K, typename V, typename... Args>
V GetWithDef(const C<K,V,Args...>& m, K const& key, const V & defval)
{
typename C<K,V,Args...>::const_iterator it = m.find( key );
if (it == m.end())
return defval;
return it->second;
}
C++17 provides try_emplace which does exactly this. It takes a key and an argument list for the value constructor and returns a pair: an iterator and a bool.: http://en.cppreference.com/w/cpp/container/map/try_emplace
The C++ standard (23.3.1.2) specifies that the newly inserted value is default constructed, so map itself doesn't provide a way of doing it. Your choices are:
Give the value type a default constructor that initialises it to the value you want, or
Wrap the map in your own class that provides a default value and implements operator[] to insert that default.
The value is initialized using the default constructor, as the other answers say. However, it is useful to add that in case of simple types (integral types such as int, float, pointer or POD (plan old data) types), the values are zero-initialized (or zeroed by value-initialization (which is effectively the same thing), depending on which version of C++ is used).
Anyway, the bottomline is, that maps with simple types will zero-initialize the new items automatically. So in some cases, there is no need to worry about explicitly specifying the default initial value.
std::map<int, char*> map;
typedef char *P;
char *p = map[123],
*p1 = P(); // map uses the same construct inside, causes zero-initialization
assert(!p && !p1); // both will be 0
See Do the parentheses after the type name make a difference with new? for more details on the matter.
There is no way to specify the default value - it is always value constructed by the default (zero parameter constructor).
In fact operator[] probably does more than you expect as if a value does not exist for the given key in the map it will insert a new one with the value from the default constructor.
template<typename T, T X>
struct Default {
Default () : val(T(X)) {}
Default (T const & val) : val(val) {}
operator T & () { return val; }
operator T const & () const { return val; }
T val;
};
<...>
std::map<KeyType, Default<ValueType, DefaultValue> > mapping;
More General Version, Support C++98/03 and More Containers
Works with generic associative containers, the only template parameter is the container type itself.
Supported containers: std::map, std::multimap, std::unordered_map, std::unordered_multimap, wxHashMap, QMap, QMultiMap, QHash, QMultiHash, etc.
template<typename MAP>
const typename MAP::mapped_type& get_with_default(const MAP& m,
const typename MAP::key_type& key,
const typename MAP::mapped_type& defval)
{
typename MAP::const_iterator it = m.find(key);
if (it == m.end())
return defval;
return it->second;
}
Usage:
std::map<int, std::string> t;
t[1] = "one";
string s = get_with_default(t, 2, "unknown");
Here is a similar implementation by using a wrapper class, which is more similar to the method get() of dict type in Python: https://github.com/hltj/wxMEdit/blob/master/src/xm/xm_utils.hpp
template<typename MAP>
struct map_wrapper
{
typedef typename MAP::key_type K;
typedef typename MAP::mapped_type V;
typedef typename MAP::const_iterator CIT;
map_wrapper(const MAP& m) :m_map(m) {}
const V& get(const K& key, const V& default_val) const
{
CIT it = m_map.find(key);
if (it == m_map.end())
return default_val;
return it->second;
}
private:
const MAP& m_map;
};
template<typename MAP>
map_wrapper<MAP> wrap_map(const MAP& m)
{
return map_wrapper<MAP>(m);
}
Usage:
std::map<int, std::string> t;
t[1] = "one";
string s = wrap_map(t).get(2, "unknown");
One workaround is to use map::at() instead of [].
If a key does not exist, at throws an exception.
Even nicer, this also works for vectors, and is thus suited for generic programming where you may swap the map with a vector.
Using a custom value for unregistered key may be dangerous since that custom value (like -1) may be processed further down in the code. With exceptions, it's easier to spot bugs.
Expanding on the answer https://stackoverflow.com/a/2333816/272642, this template function uses std::map's key_type and mapped_type typedefs to deduce the type of key and def.
This doesn't work with containers without these typedefs.
template <typename C>
typename C::mapped_type getWithDefault(const C& m, const typename C::key_type& key, const typename C::mapped_type& def) {
typename C::const_iterator it = m.find(key);
if (it == m.end())
return def;
return it->second;
}
This allows you to use
std::map<std::string, int*> m;
int* v = getWithDefault(m, "a", NULL);
without needing to cast the arguments like std::string("a"), (int*) NULL.
Pre-C++17, use std::map::insert(), for newer versions use try_emplace(). It may be counter-intuitive, but these functions effectively have the behaviour of operator[] with custom default values.
Realizing that I'm quite late to this party, but if you're interested in the behaviour of operator[] with custom defaults (that is: find the element with the given key, if it isn't present insert a chosen default value and return a reference to either the newly inserted value or the existing value), there is already a function available to you pre C++17: std::map::insert(). insert will not actually insert if the key already exists, but instead return an iterator to the existing value.
Say, you wanted a map of string-to-int and insert a default value of 42 if the key wasn't present yet:
std::map<std::string, int> answers;
int count_answers( const std::string &question)
{
auto &value = answers.insert( {question, 42}).first->second;
return value++;
}
int main() {
std::cout << count_answers( "Life, the universe and everything") << '\n';
std::cout << count_answers( "Life, the universe and everything") << '\n';
std::cout << count_answers( "Life, the universe and everything") << '\n';
return 0;
}
which should output 42, 43 and 44.
If the cost of constructing the map value is high (if either copying/moving the key or the value type is expensive), this comes at a significant performance penalty, which would be circumvented with C++17's try_emplace().
If you have access to C++17, my solution is as follows:
std::map<std::string, std::optional<int>> myNullables;
std::cout << myNullables["empty-key"].value_or(-1) << std::endl;
This allows you to specify a 'default value' at each use of the map. This may not necessarily be what you want or need, but I'll post it here for the sake of completeness. This solution lends itself well to a functional paradigm, as maps (and dictionaries) are often used with such a style anyway:
Map<String, int> myNullables;
print(myNullables["empty-key"] ?? -1);
Maybe you can give a custom allocator who allocate with a default value you want.
template < class Key, class T, class Compare = less<Key>,
class Allocator = allocator<pair<const Key,T> > > class map;
With C++20 it is simple to write such getter:
constexpr auto &getOrDefault(const auto &map, const auto &key, const auto &defaultValue)
{
const auto itr = map.find(key);
return itr == map.cend() ? defaultValue : itr->second;
}
Here is a correct approach that will conditionally return a reference if the caller passes in an lvalue reference to the mapped type.
template <typename Map, typename DefVal>
using get_default_return_t = std::conditional_t<std::is_same_v<std::decay_t<DefVal>,
typename Map::mapped_type> && std::is_lvalue_reference_v<DefVal>,
const typename Map::mapped_type&, typename Map::mapped_type>;
template <typename Map, typename Key, typename DefVal>
get_default_return_t<Map, DefVal> get_default(const Map& map, const Key& key, DefVal&& defval)
{
auto i = map.find(key);
return i != map.end() ? i->second : defval;
}
int main()
{
std::map<std::string, std::string> map;
const char cstr[] = "world";
std::string str = "world";
auto& ref = get_default(map, "hello", str);
auto& ref2 = get_default(map, "hello", std::string{"world"}); // fails to compile
auto& ref3 = get_default(map, "hello", cstr); // fails to compile
return 0;
}
If you would like to keep using operator[] just like when you don't have to specify a default value other than what comes out from T() (where T is the value type), you can inherit T and specify a different default value in the constructor:
#include <iostream>
#include <map>
#include <string>
int main() {
class string_with_my_default : public std::string {
public:
string_with_my_default() : std::string("my default") {}
};
std::map<std::string, string_with_my_default> m;
std::cout << m["first-key"] << std::endl;
}
However, if T is a primitive type, try this:
#include <iostream>
#include <map>
#include <string>
template <int default_val>
class int_with_my_default {
private:
int val = default_val;
public:
operator int &() { return val; }
int* operator &() { return &val; }
};
int main() {
std::map<std::string, int_with_my_default<1> > m;
std::cout << m["first-key"] << std::endl;
++ m["second-key"];
std::cout << m["second-key"] << std::endl;
}
See also C++ Class wrapper around fundamental types