Advice on a better way to extend C++ STL container with user-defined methods
why you need extend vector in this way?
use standard <algorithm>
with your functors.
e.g.
std::min_element
, std::max_element
int max_a = std::max_element
(
v.begin(),
v.end(),
boost::bind(
std::less< int >(),
bind( &Item::a, _1 ),
bind( &Item::a, _2 )
)
)->a;
std::accumulate
- for calculate avarage
const double avg_c = std::accumulate( v.begin(), v.end(), double( 0 ), boost::bind( Item::c, _1 ) ) / v.size(); // ofcourse check size before divide
your ItemList::SpecialB() could be rewrited as:
int accumulate_func( int start_from, int result, const Item& item )
{
if ( item.SpecialB() < start_from )
{
result -= item.SpecialB();
}
return result;
}
if ( v.empty() )
{
throw sometghing( "empty vector" );
}
const int result = std::accumulate( v.begin(), v.end(), v.front(), boost::bind( &accumulate_func, v.front(), _1, _2 ) );
BTW: if you don't need access to members, you don't need inheritance.
How can I extend stl classes to have my own methods?
You should use free functions:
template<typename... Args>
bool has_key(std::map<Args...> const& map, typename std::map<Args...>::key_type key) {
return map.find(key) != map.end();
}
Don't use inheritance if it's not necesarry. That's silly.
Extension of STL container through composition or free functions?
Hashing is an algorithm not a type, and probably shouldn't be restricted to data in any particular container type either. If you want to provide hashing, it probably makes the most sense to create a functor that computes a hash one element (int
, as you've written things above) at a time, then use std::accumulate
or std::for_each
to apply that to a collection:
namespace whatever {
struct hasher {
int current_hash;
public:
hasher() : current_hash(0x1234) {}
// incredibly simplistic hash: just XOR the values together.
operator()(int new_val) { current_hash ^= new_val; }
operator int() { return current_hash; }
};
}
int hash = std::for_each(coll.begin(), coll.end(), whatever::hasher());
Note that this allows coll
to be a vector
, or a deque
or you can use a pair of istream_iterators
to hash data in a file...
Adding specialized functionality to STL containers
I think the immediate cause of your error is that you need typename
:
typename std::list<T>::iterator i, e = this.short_list.end();
... because the compiler doesn't realize that iterator
is a type yet.
But you really don't want to derive from std::list
, and you don't want to write your own sort.
Algorithmic efficiency of each C++ STL collection operations
Most online references include such data (other than benchmarks, which I believe aren't very useful for most people, if not done by themselves).
For example, look at http://en.cppreference.com/w/
It has a 'Complexity' field for most methods.
Is it okay to inherit implementation from STL containers, rather than delegate?
The risk is deallocating through a pointer to the base class (delete, delete[], and potentially other deallocation methods). Since these classes (deque, map, string, etc.) don't have virtual dtors, it's impossible to clean them up properly with only a pointer to those classes:
struct BadExample : vector<int> {};
int main() {
vector<int>* p = new BadExample();
delete p; // this is Undefined Behavior
return 0;
}
That said, if you're willing to make sure you never accidentally do this, there's little major drawback to inheriting them—but in some cases that's a big if. Other drawbacks include clashing with implementation specifics and extensions (some of which may not use reserved identifiers) and dealing with bloated interfaces (string in particular). However, inheritance is intended in some cases, as container adapters like stack have a protected member c (the underlying container they adapt), and it's almost only accessible from a derived class instance.
Instead of either inheritance or composition, consider writing free functions which take either an iterator pair or a container reference, and operate on that. Practically all of <algorithm> is an example of this; and make_heap, pop_heap, and push_heap, in particular, are an example of using free functions instead of a domain-specific container.
So, use the container classes for your data types, and still call the free functions for your domain-specific logic. But you can still achieve some modularity using a typedef, which allows you to both simplify declaring them and provides a single point if part of them needs to change:
typedef std::deque<int, MyAllocator> Example;
// ...
Example c (42);
example_algorithm(c);
example_algorithm2(c.begin() + 5, c.end() - 5);
Example::iterator i; // nested types are especially easier
Notice the value_type and allocator can change without affecting later code using the typedef, and even the container can change from a deque to a vector.
Is there a better way to check if a STL container is a multi* container
Seeing as there are a small finite number of std::multi*
containers, you can just list them:
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
#include <type_traits>
template <typename Container>
struct is_multi_container :
std::false_type
{};
template <typename T, typename Compare, typename Alloc>
struct is_multi_container<std::multiset<T, Compare, Alloc>> :
std::true_type
{};
template <typename T, typename Compare, typename Alloc>
struct is_multi_container<std::multimap<T, Compare, Alloc>> :
std::true_type
{};
template <typename T, typename Compare, typename Alloc>
struct is_multi_container<std::unordered_multiset<T, Compare, Alloc>> :
std::true_type
{};
template <typename T, typename Compare, typename Alloc>
struct is_multi_container<std::unordered_multimap<T, Compare, Alloc>> :
std::true_type
{};
More lines of code, but it's easy to read and is direct in its reasoning (i.e., it definitely works!).
Being an explicit list, the caveat is that it doesn't extend itself automatically. For that, your solution is good. C++14 may have an AssociativeContainer
concept which would make this even easier; research on this is left as an exercise for the reader. ;)
Example:
#include <iostream>
#include <iomanip>
int main()
{
std::cout << std::boolalpha;
#define TEST(type, ...) \
std::cout << type " is: " \
<< is_multi_container<__VA_ARGS__>::value \
<< std::endl
TEST("std::set<T>", std::set<int>);
TEST("std::multiset<T>", std::multiset<int>);
TEST("std::map<K,T>", std::map<int, double>);
TEST("std::multimap<K,T>", std::multimap<int, double>);
TEST("std::unordered_set<T>", std::unordered_set<int>);
TEST("std::unordered_multiset<T>", std::unordered_multiset<int>);
TEST("std::unordered_map<K,T>", std::unordered_map<int, double>);
TEST("std::unordered_multimap<K,T>", std::unordered_multimap<int, double>);
}
Output:
std::set<T> is: false
std::multiset<T> is: true
std::map<K,T> is: false
std::multimap<K,T> is: true
std::unordered_set<T> is: false
std::unordered_multiset<T> is: true
std::unordered_map<K,T> is: false
std::unordered_multimap<K,T> is: true
Adding custom methods to std::vector or typdef
You can't do that: C++ doesn't have extension methods similar to what you have in C#.
You could derive your class from vector, but then you have to change all the client code. Besides, as Roddy points out, std::vector doesn't have a virtual destructor, so deriving from it is a bad idea in general.
IMO, writing a simple function would be much better choice. Additional benefit is that it would also work for most other containers (e.g. std::list
) and be more compatible with most of algorithms in STL which are also typically free functions.
So you would have this instead:
myNewSearchFunction(v, "ivor"); // instead of v.myNewSearchFunction("ivor");
Internally, this function does std::find_if(v.begin(), v.end(), ...
.
BTW, please note that it would be better to use std::begin(v), std::end(v)
than v.begin(), v.end()
. This lets you run the same code on e.g. arrays.
Putting things into classes isn't always the best choice in C++.
C++ extend a vector with another vector
From here
// reserve() is optional - just to improve performance
v.reserve(v.size() + distance(v_prime.begin(),v_prime.end()));
v.insert(v.end(),v_prime.begin(),v_prime.end());
Related Topics
Pointers to Virtual Member Functions. How Does It Work
C++ Boost Asio Simple Periodic Timer
C++11 Virtual Destructors and Auto Generation of Move Special Functions
C++ - How to Find the Length of an Integer
Why Isn't Rvo Applied to Base Class Subobject Initialization
Long Long Implementation in 32 Bit MAChine
Same Class Name in Different C++ Files
Use of Typename Keyword with Typedef and New
How to Detect Whether Windows Is Shutting Down or Restarting
Lto, Devirtualization, and Virtual Tables
The Implementation of Random_Device in VS2010
What Is the Ascii Value of Eof in C
Does Std::Mutex Create a Fence
Does the Restrict Keyword Provide Significant Benefits in Gcc/G++