How to initialize static vector member? - c++

For example
struct A
{
static vector<int> s;
};
vector<int> A::s = {1, 2, 3};
However, my compiler doesn't support initialization list. Any way to implement it easily? Does lambda function help here?

Any way to implement it easily?
There's nothing particularly elegant. You can either copy the data from a static array, or initialise it with the result of a function call. The former might use more memory than you'd like, and the latter needs some slightly messy code.
Boost has a library to make that slightly less ugly:
#include <boost/assign/list_of.hpp>
vector<int> A::s = boost::assign::list_of(1)(2)(3);
Does lambda function help here?
Yes, it can save you from having to name a function just to initialise the vector:
vector<int> A::s = [] {
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
return v;
}();
(Strictly speaking, this should have an explicit return type, []()->vector<int>, since the lambda body contains more than just a return statement. Some compilers will accept my version, and I believe it will become standard in 2014.)

I always fear being shot down for initialization ordering here for questions like this, but..
#include <iostream>
#include <vector>
#include <iterator>
struct A
{
static std::vector<int> s;
};
static const int s_data[] = { 1,2,3 };
std::vector<int> A::s(std::begin(s_data), std::end(s_data));
int main()
{
std::copy(A::s.begin(), A::s.end(),
std::ostream_iterator<int>(std::cout, " "));
return 0;
}
Output
1 2 3
Just because you can doesn't mean you should =P
Winning the award for the least efficient way to do this:
#include <iostream>
#include <vector>
#include <cstdlib>
using namespace std;
template<typename T>
std::vector<T> v_init(const T& t)
{
return std::vector<T>(1,t);
}
template<typename T, typename... Args>
std::vector<T> v_init(T&& t, Args&&... args)
{
const T values[] = { t, args... };
std::vector<T> v1(std::begin(values), std::end(values));
return v1;
}
struct A
{
static std::vector<int> s;
};
std::vector<int> A::s(v_init(1,2,3,4,5));
int main(int argc, const char *argv[])
{
std::copy(A::s.begin(), A::s.end(), std::ostream_iterator<int>(std::cout, " "));
return 0;
}
Output
1 2 3 4 5
This should puke at compile-time if T and anything in Args... is not type-compliant or type-castable. Of course, if you have variadic templates odds are you also have initializer lists, but it makes for fun brain-food if nothing else.

Write a simple init function for the vector:
vector<int> init()
{
vector<int> v;
v.reserve(3);
v.push_back(1);
v.push_back(2);
v.push_back(3);
return v;
};
vector<int> A::s = init();

You can initialize an std::vector from two pointers
int xv[] = {1,2,3,4,5,6,7,8,9};
std::vector<int> x(xv, xv+(sizeof(xv)/sizeof(xv[0])));
You can even factor this out in a template function:
template<typename T, int n>
std::vector<T> from_array(T (&v)[n]) {
return std::vector<T>(v, v+n);
}

Another idea:
struct A
{
static std::vector<int> s;
};
std::vector<int> A::s;
static bool dummy((A::s.push_back(1), A::s.push_back(2), A::s.push_back(3), false));

Related

How to add an unsigned char array after one unsigned char array and return a unsigned char pointer point to the combined new array? [duplicate]

How do I concatenate two std::vectors?
vector1.insert( vector1.end(), vector2.begin(), vector2.end() );
If you are using C++11, and wish to move the elements rather than merely copying them, you can use std::move_iterator along with insert (or copy):
#include <vector>
#include <iostream>
#include <iterator>
int main(int argc, char** argv) {
std::vector<int> dest{1,2,3,4,5};
std::vector<int> src{6,7,8,9,10};
// Move elements from src to dest.
// src is left in undefined but safe-to-destruct state.
dest.insert(
dest.end(),
std::make_move_iterator(src.begin()),
std::make_move_iterator(src.end())
);
// Print out concatenated vector.
std::copy(
dest.begin(),
dest.end(),
std::ostream_iterator<int>(std::cout, "\n")
);
return 0;
}
This will not be more efficient for the example with ints, since moving them is no more efficient than copying them, but for a data structure with optimized moves, it can avoid copying unnecessary state:
#include <vector>
#include <iostream>
#include <iterator>
int main(int argc, char** argv) {
std::vector<std::vector<int>> dest{{1,2,3,4,5}, {3,4}};
std::vector<std::vector<int>> src{{6,7,8,9,10}};
// Move elements from src to dest.
// src is left in undefined but safe-to-destruct state.
dest.insert(
dest.end(),
std::make_move_iterator(src.begin()),
std::make_move_iterator(src.end())
);
return 0;
}
After the move, src's element is left in an undefined but safe-to-destruct state, and its former elements were transfered directly to dest's new element at the end.
I would use the insert function, something like:
vector<int> a, b;
//fill with data
b.insert(b.end(), a.begin(), a.end());
Or you could use:
std::copy(source.begin(), source.end(), std::back_inserter(destination));
This pattern is useful if the two vectors don't contain exactly the same type of thing, because you can use something instead of std::back_inserter to convert from one type to the other.
With C++11, I'd prefer following to append vector b to a:
std::move(b.begin(), b.end(), std::back_inserter(a));
when a and b are not overlapped, and b is not going to be used anymore.
This is std::move from <algorithm>, not the usual std::move from <utility>.
std::vector<int> first;
std::vector<int> second;
first.insert(first.end(), second.begin(), second.end());
I prefer one that is already mentioned:
a.insert(a.end(), b.begin(), b.end());
But if you use C++11, there is one more generic way:
a.insert(std::end(a), std::begin(b), std::end(b));
Also, not part of a question, but it is advisable to use reserve before appending for better performance. And if you are concatenating vector with itself, without reserving it fails, so you always should reserve.
So basically what you need:
template <typename T>
void Append(std::vector<T>& a, const std::vector<T>& b)
{
a.reserve(a.size() + b.size());
a.insert(a.end(), b.begin(), b.end());
}
With range v3, you may have a lazy concatenation:
ranges::view::concat(v1, v2)
Demo.
A general performance boost for concatenate is to check the size of the vectors. And merge/insert the smaller one with the larger one.
//vector<int> v1,v2;
if(v1.size()>v2.size()) {
v1.insert(v1.end(),v2.begin(),v2.end());
} else {
v2.insert(v2.end(),v1.begin(),v1.end());
}
If you want to be able to concatenate vectors concisely, you could overload the += operator.
template <typename T>
std::vector<T>& operator +=(std::vector<T>& vector1, const std::vector<T>& vector2) {
vector1.insert(vector1.end(), vector2.begin(), vector2.end());
return vector1;
}
Then you can call it like this:
vector1 += vector2;
There is an algorithm std::merge from C++17, which is very easy to use when the input vectors are sorted,
Below is the example:
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
//DATA
std::vector<int> v1{2,4,6,8};
std::vector<int> v2{12,14,16,18};
//MERGE
std::vector<int> dst;
std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(dst));
//PRINT
for(auto item:dst)
std::cout<<item<<" ";
return 0;
}
You should use vector::insert
v1.insert(v1.end(), v2.begin(), v2.end());
If you are interested in strong exception guarantee (when copy constructor can throw an exception):
template<typename T>
inline void append_copy(std::vector<T>& v1, const std::vector<T>& v2)
{
const auto orig_v1_size = v1.size();
v1.reserve(orig_v1_size + v2.size());
try
{
v1.insert(v1.end(), v2.begin(), v2.end());
}
catch(...)
{
v1.erase(v1.begin() + orig_v1_size, v1.end());
throw;
}
}
Similar append_move with strong guarantee can't be implemented in general if vector element's move constructor can throw (which is unlikely but still).
If your goal is simply to iterate over the range of values for read-only purposes, an alternative is to wrap both vectors around a proxy (O(1)) instead of copying them (O(n)), so they are promptly seen as a single, contiguous one.
std::vector<int> A{ 1, 2, 3, 4, 5};
std::vector<int> B{ 10, 20, 30 };
VecProxy<int> AB(A, B); // ----> O(1)!
for (size_t i = 0; i < AB.size(); i++)
std::cout << AB[i] << " "; // ----> 1 2 3 4 5 10 20 30
Refer to https://stackoverflow.com/a/55838758/2379625 for more details, including the 'VecProxy' implementation as well as pros & cons.
Add this one to your header file:
template <typename T> vector<T> concat(vector<T> &a, vector<T> &b) {
vector<T> ret = vector<T>();
copy(a.begin(), a.end(), back_inserter(ret));
copy(b.begin(), b.end(), back_inserter(ret));
return ret;
}
and use it this way:
vector<int> a = vector<int>();
vector<int> b = vector<int>();
a.push_back(1);
a.push_back(2);
b.push_back(62);
vector<int> r = concat(a, b);
r will contain [1,2,62]
Using C++20 you can get rid of begin() and end() with ranges.
#include <ranges>
std::ranges::copy(vec2, std::back_inserter(vec1));
or if you want to move elements:
std::ranges::move(vec2, std::back_inserter(vec1));
Here's a general purpose solution using C++11 move semantics:
template <typename T>
std::vector<T> concat(const std::vector<T>& lhs, const std::vector<T>& rhs)
{
if (lhs.empty()) return rhs;
if (rhs.empty()) return lhs;
std::vector<T> result {};
result.reserve(lhs.size() + rhs.size());
result.insert(result.cend(), lhs.cbegin(), lhs.cend());
result.insert(result.cend(), rhs.cbegin(), rhs.cend());
return result;
}
template <typename T>
std::vector<T> concat(std::vector<T>&& lhs, const std::vector<T>& rhs)
{
lhs.insert(lhs.cend(), rhs.cbegin(), rhs.cend());
return std::move(lhs);
}
template <typename T>
std::vector<T> concat(const std::vector<T>& lhs, std::vector<T>&& rhs)
{
rhs.insert(rhs.cbegin(), lhs.cbegin(), lhs.cend());
return std::move(rhs);
}
template <typename T>
std::vector<T> concat(std::vector<T>&& lhs, std::vector<T>&& rhs)
{
if (lhs.empty()) return std::move(rhs);
lhs.insert(lhs.cend(), std::make_move_iterator(rhs.begin()), std::make_move_iterator(rhs.end()));
return std::move(lhs);
}
Note how this differs from appending to a vector.
You can prepare your own template for + operator:
template <typename T>
inline T operator+(const T & a, const T & b)
{
T res = a;
res.insert(res.end(), b.begin(), b.end());
return res;
}
Next thing - just use +:
vector<int> a{1, 2, 3, 4};
vector<int> b{5, 6, 7, 8};
for (auto x: a + b)
cout << x << " ";
cout << endl;
This example gives output:
1 2 3 4 5 6 7 8
vector<int> v1 = {1, 2, 3, 4, 5};
vector<int> v2 = {11, 12, 13, 14, 15};
copy(v2.begin(), v2.end(), back_inserter(v1));
I've implemented this function which concatenates any number of containers, moving from rvalue-references and copying otherwise
namespace internal {
// Implementation detail of Concatenate, appends to a pre-reserved vector, copying or moving if
// appropriate
template<typename Target, typename Head, typename... Tail>
void AppendNoReserve(Target* target, Head&& head, Tail&&... tail) {
// Currently, require each homogenous inputs. If there is demand, we could probably implement a
// version that outputs a vector whose value_type is the common_type of all the containers
// passed to it, and call it ConvertingConcatenate.
static_assert(
std::is_same_v<
typename std::decay_t<Target>::value_type,
typename std::decay_t<Head>::value_type>,
"Concatenate requires each container passed to it to have the same value_type");
if constexpr (std::is_lvalue_reference_v<Head>) {
std::copy(head.begin(), head.end(), std::back_inserter(*target));
} else {
std::move(head.begin(), head.end(), std::back_inserter(*target));
}
if constexpr (sizeof...(Tail) > 0) {
AppendNoReserve(target, std::forward<Tail>(tail)...);
}
}
template<typename Head, typename... Tail>
size_t TotalSize(const Head& head, const Tail&... tail) {
if constexpr (sizeof...(Tail) > 0) {
return head.size() + TotalSize(tail...);
} else {
return head.size();
}
}
} // namespace internal
/// Concatenate the provided containers into a single vector. Moves from rvalue references, copies
/// otherwise.
template<typename Head, typename... Tail>
auto Concatenate(Head&& head, Tail&&... tail) {
size_t totalSize = internal::TotalSize(head, tail...);
std::vector<typename std::decay_t<Head>::value_type> result;
result.reserve(totalSize);
internal::AppendNoReserve(&result, std::forward<Head>(head), std::forward<Tail>(tail)...);
return result;
}
This solution might be a bit complicated, but boost-range has also some other nice things to offer.
#include <iostream>
#include <vector>
#include <boost/range/algorithm/copy.hpp>
int main(int, char**) {
std::vector<int> a = { 1,2,3 };
std::vector<int> b = { 4,5,6 };
boost::copy(b, std::back_inserter(a));
for (auto& iter : a) {
std::cout << iter << " ";
}
return EXIT_SUCCESS;
}
Often ones intention is to combine vector a and b just iterate over it doing some operation. In this case, there is the ridiculous simple join function.
#include <iostream>
#include <vector>
#include <boost/range/join.hpp>
#include <boost/range/algorithm/copy.hpp>
int main(int, char**) {
std::vector<int> a = { 1,2,3 };
std::vector<int> b = { 4,5,6 };
std::vector<int> c = { 7,8,9 };
// Just creates an iterator
for (auto& iter : boost::join(a, boost::join(b, c))) {
std::cout << iter << " ";
}
std::cout << "\n";
// Can also be used to create a copy
std::vector<int> d;
boost::copy(boost::join(a, boost::join(b, c)), std::back_inserter(d));
for (auto& iter : d) {
std::cout << iter << " ";
}
return EXIT_SUCCESS;
}
For large vectors this might be an advantage, as there is no copying. It can be also used for copying an generalizes easily to more than one container.
For some reason there is nothing like boost::join(a,b,c), which could be reasonable.
For containers which offer push_back (string, vector, deque, ...):
std::copy(std::begin(input), std::end(input), std::back_inserter(output))
and
for containers which offer insert (maps, sets):
std::copy(std::begin(input), std::end(input), std::inserter(output, output.end()))
If what you're looking for is a way to append a vector to another after creation, vector::insert is your best bet, as has been answered several times, for example:
vector<int> first = {13};
const vector<int> second = {42};
first.insert(first.end(), second.cbegin(), second.cend());
Sadly there's no way to construct a const vector<int>, as above you must construct and then insert.
If what you're actually looking for is a container to hold the concatenation of these two vector<int>s, there may be something better available to you, if:
Your vector contains primitives
Your contained primitives are of size 32-bit or smaller
You want a const container
If the above are all true, I'd suggest using the basic_string who's char_type matches the size of the primitive contained in your vector. You should include a static_assert in your code to validate these sizes stay consistent:
static_assert(sizeof(char32_t) == sizeof(int));
With this holding true you can just do:
const u32string concatenation = u32string(first.cbegin(), first.cend()) + u32string(second.cbegin(), second.cend());
For more information on the differences between string and vector you can look here: https://stackoverflow.com/a/35558008/2642059
For a live example of this code you can look here: http://ideone.com/7Iww3I
You can do it with pre-implemented STL algorithms using a template for a polymorphic type use.
#include <iostream>
#include <vector>
#include <algorithm>
template<typename T>
void concat(std::vector<T>& valuesa, std::vector<T>& valuesb){
for_each(valuesb.begin(), valuesb.end(), [&](int value){ valuesa.push_back(value);});
}
int main()
{
std::vector<int> values_p={1,2,3,4,5};
std::vector<int> values_s={6,7};
concat(values_p, values_s);
for(auto& it : values_p){
std::cout<<it<<std::endl;
}
return 0;
}
You can clear the second vector if you don't want to use it further (clear() method).
Concatenate two std::vector-s with for loop in one std::vector.
std::vector <int> v1 {1, 2, 3}; //declare vector1
std::vector <int> v2 {4, 5}; //declare vector2
std::vector <int> suma; //declare vector suma
for(int i = 0; i < v1.size(); i++) //for loop 1
{
suma.push_back(v1[i]);
}
for(int i = 0; i< v2.size(); i++) //for loop 2
{
suma.push_back(v2[i]);
}
for(int i = 0; i < suma.size(); i++) //for loop 3-output
{
std::cout << suma[i];
}
To be honest, you could fast concatenate two vectors by copy elements from two vectors into the other one or just only append one of two vectors!. It depends on your aim.
Method 1: Assign new vector with its size is the sum of two original vectors' size.
vector<int> concat_vector = vector<int>();
concat_vector.setcapacity(vector_A.size() + vector_B.size());
// Loop for copy elements in two vectors into concat_vector
Method 2: Append vector A by adding/inserting elements of vector B.
// Loop for insert elements of vector_B into vector_A with insert()
function: vector_A.insert(vector_A .end(), vector_B.cbegin(), vector_B.cend());
Try, create two vectors and add second vector to first vector,
code:
std::vector<int> v1{1,2,3};
std::vector<int> v2{4,5};
for(int i = 0; i<v2.size();i++)
{
v1.push_back(v2[i]);
}
v1:1,2,3.
Description:
While i int not v2 size, push back element , index i in v1 vector.

Initialize static std::map with unique_ptr as value

How can one initialize static map, where value is std::unique_ptr?
static void f()
{
static std::map<int, std::unique_ptr<MyClass>> = {
{ 0, std::make_unique<MyClass>() }
};
}
Of course this does not work (copy-ctor of std::unique_ptr is deleted).
Is it possible?
The Problem is that constructing from std::initializer-list copies its contents. (objects in std::initializer_list are inherently const).
To solve your problem: You can initialize the map from a separate function...
std::map<int, std::unique_ptr<MyClass>> init(){
std::map<int, std::unique_ptr<MyClass>> mp;
mp[0] = std::make_unique<MyClass>();
mp[1] = std::make_unique<MyClass>();
//...etc
return mp;
}
And then call it
static void f()
{
static std::map<int, std::unique_ptr<MyClass>> mp = init();
}
See it Live On Coliru
Writing bespoke crestion code seems boring and gets in the way of clarity.
Here is reasonably efficient generic container initialization code. It stores your data in a temporary std::array like an initializer list does, but it moves out instead of making it const.
The make_map takes an even number of elements, the first being key the second value.
template<class E, std::size_t N>
struct make_container_t{
std::array<E,N> elements;
template<class Container>
operator Container()&&{
return {
std::make_move_iterator(begin(elements)),
std::make_move_iterator(end(elements))
};
}
};
template<class E0, class...Es>
make_container_t<E0, 1+sizeof...(Es)>
make_container( E0 e0, Es... es ){
return {{{std::move(e0), std::move(es)...}}};
}
namespace details{
template<std::size_t...Is, class K0, class V0, class...Ts>
make_container_t<std::pair<K0,V0>,sizeof...(Is)>
make_map( std::index_sequence<Is...>, std::tuple<K0&,V0&,Ts&...> ts ){
return {{{
std::make_pair(
std::move(std::get<Is*2>(ts)),
std::move(std::get<Is*2+1>(ts))
)...
}}};
}
}
template<class...Es>
auto make_map( Es... es ){
static_assert( !(sizeof...(es)&1), "key missing a value? Try even arguments.");
return details::make_map(
std::make_index_sequence<sizeof...(Es)/2>{},
std::tie( es... )
);
}
This should reduce it to:
static std::map<int, std::unique_ptr<MyClass>> bob =
make_map(0, std::make_unique<MyClass>());
... barring typos.
Live example.
another way to do this is to use a lambda. it's the same as using a separate function but puts the map's initialisation closer to the action. In this case I've used a combination of an auto& and decltype to avoid having to name the type of the map, but that's just for fun.
Note that the argument passed into the lambda is a reference to an object that has not yet been constructed at the point of the call, so we must not reference it in any way. It's only used for type deduction.
#include <memory>
#include <map>
#include <utility>
struct MyClass {};
static auto& f()
{
static std::map<int, std::unique_ptr<MyClass>> mp = [](auto& model)
{
auto mp = std::decay_t<decltype(model)> {};
mp.emplace(0, std::make_unique<MyClass>());
mp.emplace(1, std::make_unique<MyClass>());
return mp;
}(mp);
return mp;
}
int main()
{
auto& m = f();
}
Here's another way. In this case we've passed a temporary into the lambda and relied on copy elision/RVO.
#include <memory>
#include <map>
#include <utility>
struct MyClass {};
static auto& f()
{
static auto mp = [](auto mp)
{
mp.emplace(0, std::make_unique<MyClass>());
mp.emplace(1, std::make_unique<MyClass>());
return mp;
}(std::map<int, std::unique_ptr<MyClass>>{});
return mp;
}
int main()
{
auto& m = f();
}
And yet another way, using a lambda capture in a mutable lambda.
#include <memory>
#include <map>
#include <utility>
struct MyClass {};
static auto& f()
{
static auto mp = [mp = std::map<int, std::unique_ptr<MyClass>>{}]() mutable
{
mp.emplace(0, std::make_unique<MyClass>());
mp.emplace(1, std::make_unique<MyClass>());
return std::move(mp);
}();
return mp;
}
int main()
{
auto& m = f();
}

Is it possible to initialize a vector with increasing values in a single line?

Is it possible to merge the two initialization lines into a single statement with the help of initializer lists or other C++ features? The vector values always increment with one, but the size n is not fixed.
#include <numeric>
#include <vector>
#include <iostream>
int main()
{
int n = 10;
// Can the two lines below be combined into a single statement?
std::vector<int> v(n);
std::iota(v.begin(), v.end(), 1);
for (int i : v)
std::cout << i << std::endl;
return 0;
}
You can use Boost.counting_iterator for this:
std::vector<int> v(boost::counting_iterator<int>(1),
boost::counting_iterator<int>(n + 1));
(Live) Now whether this is worth it and easier to read than what you already have is for you to decide.
Not really, no. If n is a runtime variable, the best you could probably do is to just throw this in a function somewhere:
std::vector<int> ints(int n) {
std::vector<int> v;
v.reserve(n);
for (int i = 0; i < n; ++i) {
v.push_back(n+1);
}
return v;
}
// now it's one line?
std::vector<int> v = ints(n);
If it's compile time, you can use std::index_sequence to provide an initializer list:
template <int... Is>
std::vector<int> ints(std::integer_sequence<int, Is...> ) {
return std::vector<int>{ (Is+1)... };
}
template <int N>
std::vector<int> ints() {
return ints(std::make_integer_sequence<int, N>{});
}
But either way, you need a helper function.

Is it possible to initialize a vector from the keys in a map?

How to retrieve all keys (or values) from a std::map and put them into a vector? covers the ways to populate a std::vector from the keys in a map pre-C++11.
Is there a way to do this in C++11 using lambdas, etc, that means we can do it in one line so we can initialize the vector from the map instead of create a vector and populate it in 2 actions?
e.g. vector<int> v(???(m.begin(),m.end()));
Pure C++11 is preferred but boost is acceptable... the aim is to do this in one line without it being overly complicated and "showing off", so it's not confusing to other developers.
For comparison the "obvious" C++11 solution is:
vector<int> v;
v.reserve(m.size()); //not always needed
for(auto &x : map)
v.push_back(x.first)
Use boost::adaptor::map_keys in Boost.Range.
#include <iostream>
#include <vector>
#include <map>
#include <boost/range/adaptor/map.hpp>
int main()
{
const std::map<int, std::string> m = {
{1, "Alice"},
{2, "Bob"},
{3, "Carol"}
};
auto key_range = m | boost::adaptors::map_keys;
const std::vector<int> v(key_range.begin(), key_range.end());
for (int x : v) {
std::cout << x << std::endl;
}
}
Output:
1
2
3
There you go, C++11 one-liner :)
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <iterator>
int main(int, char**)
{
std::map<int, std::string> map {
{1, "one"},
{2, "two"},
{3, "three"}
};
std::vector<int> keys;
// Reserve enough space (constant-time)
keys.reserve(map.size());
// Retrieve the keys and store them into the vector
std::transform(map.begin(), map.end(), std::back_inserter(keys),
[](decltype(map)::value_type const &pair) {return pair.first;}
);// ^^^^^^^^^^^^^^^^^^^^^^^^^ Will benefit from C++14's auto lambdas
// Display the vector
std::copy(keys.begin(), keys.end(),
std::ostream_iterator<int>(std::cout, " "));
return 0;
}
std::transform is freaking powerful.
Something like the following would do:
#include <vector>
#include <map>
#include <boost/iterator/transform_iterator.hpp>
int main() {
std::map<std::string, int> m{{"abc", 1}, {"def", 2}};
auto extractor = [](decltype(m)::value_type const& kv) { return kv.first; };
std::vector<std::string> v(
boost::make_transform_iterator(m.begin(), extractor)
, boost::make_transform_iterator(m.end(), extractor)
);
}
Note that passing iterators to vector's constructor is the most efficient way to initialize a vector compared to solutions that use push_back or resize a vector filling it with default values first.
No, there's no way to do this in pure C++11 in one line using any of std::vectors constructor overloads, without e.g. creating your own iterator adaptor.
It's trivial to do in two lines though, e.g.:
std::vector<Key> v;
for (const auto& p : m) v.push_back(p.first);
It would also be easy to create your own iterator adaptor for this purpose, for example:
template <typename InputIt>
struct key_it : public InputIt {
key_it(InputIt it) : InputIt(it) {}
auto operator*() { return (*this)->first; }
};
// Helper function for automatic deduction of iterator type.
template <typename InputIt>
key_it<InputIt> key_adapt(InputIt it) {
return {it};
}
Now you can create and populate your std::vector in one line using:
std::vector<Key> v{key_adapt(std::begin(m)), key_adapt(std::end(m))};
Live example
A slight refinement of Quentin's solution:
std::vector<int> keys(map.size());
transform(map.begin(), map.end(), keys.begin(),
[](std::pair<int, std::string> const &p) { return p.first; });
or more readably:
std::vector<int> keys(map.size());
auto get_key = [](std::pair<int, std::string> const &p) { return p.first; };
transform(map.begin(), map.end(), keys.begin(), get_key);
probably better having:
int get_key(std::pair<int, std::string> const &p) { return p.first; }
std::vector<int> get_keys(const std::map<int, std::string> &map)
{
std::vector<int> keys(map.size());
transform(map.begin(), map.end(), keys.begin(), get_key);
return keys;
}
then calling:
std::vector<int> keys = get_keys(map);
if it's going to be used lots.
The std::vector class has two relevant constructors:
vector(std::initializer_list<T>) [C++11]
vector(InputIterator first, InputIterator last) [C++98]
The first is the new C++11 constructor that allows you to do things like:
std::vector<int> v{ 1, 2, 3 };
The second allows you to do things like:
std::vector<int> w{ v.rbegin(), v.rend() }; // 3, 2, 1
I don't see a way to use the initializer_list constructor (as you don't have the items available up-front), so your best bet would be to create a key_iterator class that works on a std::map<T, K>::iterator and returns (*i).first instead of (*i). For example:
std::vector<int> keys{ key_iterator(m.begin()), key_iterator(m.end()) };
This also requires you to write the key_iterator class, which you can use the Boost iterator adapters to simplify the task. It may be easier just to use the 2 line version.
Whoopse, I realize this does not actually answer your question (must learn to read properly)!
I would probably go with something like this:
#include <map>
#include <vector>
#include <iostream>
int main()
{
std::map<int, std::string> m =
{
{1, "A"}, {2, "B"}, {3, "C"}
};
std::vector<int> v;
v.reserve(m.size());
for(auto&& i: m)
v.emplace_back(i.first);
for(auto&& i: v)
std::cout << i << '\n';
}

Using a STL map of function pointers

I developed a scripting engine that has many built-in functions, so to call any function, my code just went into an if .. else if .. else if wall checking the name but I would like to develop a more efficient solution.
Should I use a hashmap with strings as keys and pointers as values? How could I do it by using an STL map?
EDIT:
Another point that came into my mind: of course using a map will force the compiler not to inline functions, but my inefficient approach didn't have any overhead generated by the necessity of function calls, it just executes code.
So I wonder if the overhead generated by the function call will be any better than having an if..else chain.. otherwise I could minimize the number of comparisons by checking a character at runtime (will be longer but faster).
Whatever your function signatures are:
typedef void (*ScriptFunction)(void); // function pointer type
typedef std::unordered_map<std::string, ScriptFunction> script_map;
// ...
void some_function()
{
}
// ...
script_map m;
m.emplace("blah", &some_function);
// ...
void call_script(const std::string& pFunction)
{
auto iter = m.find(pFunction);
if (iter == m.end())
{
// not found
}
(*iter->second)();
}
Note that the ScriptFunction type could be generalized to std::function</* whatever*/> so you can support any callable thing, not just exactly function pointers.
In C++11 you can do something like this :
This Interface needs only the return type and it takes care of everything else from the caller side.
#include <string>
#include <iostream>
#include <map>
#include <vector>
#include <typeinfo>
#include <typeindex>
#include <cassert>
void fun1(void){
std::cout<<"inside fun1\n";
}
int fun2(){
std::cout<<"inside fun2\n";
return 2;
}
int fun3(int a){
std::cout<<"inside fun3\n";
return a;
}
std::vector<int> fun4(){
std::cout<<"inside fun4\n";
std::vector<int> v(4,100);
return v;
}
// every function pointer will be stored as this type
typedef void (*voidFunctionType)(void);
struct Interface{
std::map<std::string,std::pair<voidFunctionType,std::type_index>> m1;
template<typename T>
void insert(std::string s1, T f1){
auto tt = std::type_index(typeid(f1));
m1.insert(std::make_pair(s1,
std::make_pair((voidFunctionType)f1,tt)));
}
template<typename T,typename... Args>
T searchAndCall(std::string s1, Args&&... args){
auto mapIter = m1.find(s1);
/*chk if not end*/
auto mapVal = mapIter->second;
// auto typeCastedFun = reinterpret_cast<T(*)(Args ...)>(mapVal.first);
auto typeCastedFun = (T(*)(Args ...))(mapVal.first);
//compare the types is equal or not
assert(mapVal.second == std::type_index(typeid(typeCastedFun)));
return typeCastedFun(std::forward<Args>(args)...);
}
};
int main(){
Interface a1;
a1.insert("fun1",fun1);
a1.insert("fun2",fun2);
a1.insert("fun3",fun3);
a1.insert("fun4",fun4);
a1.searchAndCall<void>("fun1");
int retVal = a1.searchAndCall<int>("fun3",2);
a1.searchAndCall<int>("fun2");
auto temp = a1.searchAndCall<std::vector<int>>("fun4");
return 0;
}
You can also use Boost.Function and Boost.Bind what even allows you, to some degree, to have map of heterogeneous functions:
typedef boost::function<void, void> fun_t;
typedef std::map<std::string, fun_t> funs_t;
funs_t f;
void foo() {}
void goo(std::string& p) {}
void bar(int& p) {}
f["foo"] = foo;
f["goo"] = boost::bind(goo, "I am goo");
f["bar"] = boost::bind(bar, int(17));
It can be a map of functions of compatible prototypes as well, of course.
Above answers seem to give a complete overview, this regards only your second question:
Map element retrieval by key has O(log n) complexity. Hashmap retrieval by key has O(1) complexity + a little stuff on the side in case of collisions. So if theres a good hash function for your function names, use it. Your implementation will have a standard one. It should be fine.
But be aware, that anything below a hundred elements will not benefit all too much.
The only downside of a hash map is collision. In your case, the hashmap will be relatively static. You know the function names you support. So I advise you to create a simple test case, where you call unordered_map<...>::hash_function with all your keys to make sure that nothing collides. After that, you can forget about it.
A quick google for potential improvements on hash functions got me there:
A fiew good hash functions
Maybe, depending on your naming conventions, you can improve on some aspects of the function.
Well, you can use any_map to store functions with different signatures (but calling it will be messy) and you can use int_map to call functions with a specific signature (looks nicer).
int FuncA()
{
return 1;
}
float FuncB()
{
return 2;
}
int main()
{
// Int map
map<string,int(*)()> int_map;
int_map["A"] = FuncA;
// Call it
cout<<int_map["A"]()<<endl;
// Add it to your map
map<string, void(*)> any_map;
any_map["A"] = FuncA;
any_map["B"] = FuncB;
// Call
cout<<reinterpret_cast<float(*)()>(any_map["B"])()<<endl;
}
I've managed to modify the example from Mohit to work on member function pointers:
#include <string>
#include <iostream>
#include <map>
#include <vector>
#include <typeinfo>
#include <typeindex>
#include <cassert>
template <typename A>
using voidFunctionType = void (A::*)(void);
template <typename A>
struct Interface{
std::map<std::string,std::pair<voidFunctionType<A>,std::type_index>> m1;
template<typename T>
void insert(std::string s1, T f1){
auto tt = std::type_index(typeid(f1));
m1.insert(std::make_pair(s1,
std::make_pair((voidFunctionType<A>)f1,tt)));
}
template<typename T,typename... Args>
T searchAndCall(A a, std::string s1, Args&&... args){
auto mapIter = m1.find(s1);
auto mapVal = mapIter->second;
auto typeCastedFun = (T(A::*)(Args ...))(mapVal.first);
assert(mapVal.second == std::type_index(typeid(typeCastedFun)));
return (a.*typeCastedFun)(std::forward<Args>(args)...);
}
};
class someclass {
public:
void fun1(void);
int fun2();
int fun3(int a);
std::vector<int> fun4();
};
void someclass::fun1(void){
std::cout<<"inside fun1\n";
}
int someclass::fun2(){
std::cout<<"inside fun2\n";
return 2;
}
int someclass::fun3(int a){
std::cout<<"inside fun3\n";
return a;
}
std::vector<int> someclass::fun4(){
std::cout<<"inside fun4\n";
std::vector<int> v(4,100);
return v;
}
int main(){
Interface<someclass> a1;
a1.insert("fun3",&someclass::fun3);
someclass s;
int retVal = a1.searchAndCall<int>(s, "fun3", 3);
return 0;
}