Related
Is there a way using polymorphism to have a generic for set and multiset? as follows.
Note: but only for sets, (set, multiset)
template<typename T>
void foo(parent_set<T> &s) {
// do something
}
// main
set<int> s1 = {1, 2, 3, 4, 5};
foo(s1);
multiset<int> s2 = {1, 2, 2, 2, 2, 3};
foo(s2);
Well, why don't you make the whole container your template parameter?
template <class SetType>
void foo( SetType& s)
{
using T = typename SetType :: value_type;
enter code here
....
}
The restriction for the parameter to only be a set or multiset, as is usually done with templates, is enforced by the usage of the template parameter as a set. E.g. you call insert with a single parameter, and therefore you cannot pass a vector. If there is a third, unknown, container that has all the required interface, maybe it makes sense to allow it as well?
Suppose you have some hash values and want to map them to their respective strings at compile time.
Ideally, I'd love to be able to write something along the lines of:
constexpr std::map<int, std::string> map = { {1, "1"}, {2 ,"2"} };
Unfortunately, this is neither possible in C++17 nor C++2a. Nevertheless,
I tried emulating this with std::array, but can't get the size of the initializer list at compile time to actually set the type of the array correctly without explicitly specifying the size.
Here is my mockup:
template<typename T0, typename T1>
struct cxpair
{
using first_type = T0;
using second_type = T1;
// interestingly, we can't just = default for some reason...
constexpr cxpair()
: first(), second()
{ }
constexpr cxpair(first_type&& first, second_type&& second)
: first(first), second(second)
{ }
// std::pair doesn't have these as constexpr
constexpr cxpair& operator=(cxpair<T0, T1>&& other)
{ first = other.first; second = other.second; return *this; }
constexpr cxpair& operator=(const cxpair<T0, T1>& other)
{ first = other.first; second = other.second; return *this; }
T0 first;
T1 second;
};
template<typename Key, typename Value, std::size_t Size = 2>
struct map
{
using key_type = Key;
using mapped_type = Value;
using value_type = cxpair<Key, Value>;
constexpr map(std::initializer_list<value_type> list)
: map(list.begin(), list.end())
{ }
template<typename Itr>
constexpr map(Itr begin, const Itr &end)
{
std::size_t size = 0;
while (begin != end) {
if (size >= Size) {
throw std::range_error("Index past end of internal data size");
} else {
auto& v = data[size++];
v = std::move(*begin);
}
++begin;
}
}
// ... useful utility methods omitted
private:
std::array<value_type, Size> data;
// for the utilities, it makes sense to also have a size member, omitted for brevity
};
Now, if you just do it with plain std::array things work out of the box:
constexpr std::array<cxpair<int, std::string_view>, 2> mapp = {{ {1, "1"}, {2, "2"} }};
// even with plain pair
constexpr std::array<std::pair<int, std::string_view>, 2> mapp = {{ {1, "1"}, {2, "2"} }};
Unfortunately, we have to explicitly give the size of the array as second template argument. This is exactly what I want to avoid.
For this, I tried building the map you see up there.
With this buddy we can write stuff such as:
constexpr map<int, std::string_view> mapq = { {1, "1"} };
constexpr map<int, std::string_view> mapq = { {1, "1"}, {2, "2"} };
Unfortunately, as soon as we exceed the magic Size constant in the map, we get an error, so we need to give the size explicitly:
//// I want this to work without additional shenanigans:
//constexpr map<int, std::string_view> mapq = { {1, "1"}, {2, "2"}, {3, "3"} };
constexpr map<int, std::string_view, 3> mapq = { {1, "1"}, {2, "2"}, {3, "3"} };
Sure, as soon as you throw in the constexpr scope, you get a compile error and could just tweak the magic constant explicitly. However, this is an implementation detail I'd like to hide. The user should not need to deal with these low-level details, this is stuff the compiler should infer.
Unfortunately, I don't see a solution with the exact syntax map = { ... }. I don't even see light for things like constexpr auto map = make_map({ ... });. Besides, this is a different API from the runtime-stuff, which I'd like to avoid to increase ease of use.
So, is it somehow possible to infer this size parameter from an initializer list at compile time?
std::array has a deduction guide:
template <class T, class... U>
array(T, U...) -> array<T, 1 + sizeof...(U)>;
which lets you write:
// ok, a is array<int, 4>
constexpr std::array a = {1, 2, 3, 4};
We can follow the same principle and add a deduction guide for map like:
template <typename Key, typename Value, std::size_t Size>
struct map {
constexpr map(std::initializer_list<std::pair<Key const, Value>>) { }
};
template <class T, class... U>
map(T, U...) -> map<typename T::first_type, typename T::second_type, sizeof...(U)+1>;
Which allows:
// ok, m is map<int, int, 3>
constexpr map m = {std::pair{1, 1}, std::pair{1, 2}, std::pair{2, 3}};
Unfortunately, this approach requires naming each type in the initializer list - you can't just write {1, 2} even after you wrote pair{1, 1}.
A different way of doing it is to take an rvalue array as an argument:
template <typename Key, typename Value, std::size_t Size>
struct map {
constexpr map(std::pair<Key, Value>(&&)[Size]) { }
};
Which avoids having to write a deduction guide and lets you only have to write the type on the first one, at the cost of an extra pair of braces or parens:
// ok, n is map<int, int, 4>
constexpr map n{{std::pair{1, 1}, {1, 2}, {2, 3}, {3, 4}}};
// same
constexpr map n({std::pair{1, 1}, {1, 2}, {2, 3}, {3, 4}});
Note that the array is of pair<Key, Value> and not pair<Key const, Value> - which allows writing just pair{1, 1}. Since you're writing a constexpr map anyway, this distinction probably doesn't matter.
#Barry's answer pinpointed me in the right direction. Always explicitly listing pair in the list is undesirable. Moreover, I want to be able to partially specialize the template argument list of map. Consider the following example:
// for the sake of the example, suppose this works
constexpr map n({{1, "1"}, {2, "2"}});
// -> decltype(n) == map<int, const char*, 2>
// the following won't work
constexpr map<std::size_t, const char*> m({{1, "1"}, {2, "2"}});
However, perhaps the user wants that the map contains std::size_t as key, which does not have a literal. i.e. s/he would have to define a user-defined literal just to do that.
We can resolve this by offloading the work to a make_map function, allowing us to partially specialize the map:
// deduction guide for map's array constructor
template<class Key, class Value, std::size_t Size>
map(cxpair<Key, Value>(&&)[Size]) -> map<Key, Value, Size>;
// make_map builds the map
template<typename Key, typename Value, std::size_t Size>
constexpr auto make_map(cxpair<Key, Value>(&&m)[Size]) -> map<Key, Value, Size>
{ return map<Key, Value, Size>(std::begin(m), std::end(m)); }
// allowing us to do:
constexpr auto mapr = make_map<int, std::string_view>({ {1, "1"},
{2, "2"},
{3, "3"} });
Say I have a vector with various entries, which I want to insert into another vector, while leaving out entries that satisfy a condition.
For example, I want to insert a vector while leaving out all three's.
{1, 3, 2, 3, 4, 5, 3} -> { /* previous content, */ 1, 2, 4, 5}
What I came up with so far uses std::partition, which does not preserve the relative order and rearranges the source vector.
std::vector<int> source({1, 3, 2, 3, 4, 5, 3});
std::vector<int> target;
auto partition = std::partition(std::begin(source),
std::end(source), [](const auto& a) { return a == 3; });
target.insert(std::begin(target), partition, std::end(source));
What I am looking for is more of an iterator that checks a condition and moves on if the condition is not satisfied. Something like this:
target.insert(std::begin(target),
conditional_begin(source, [](const auto& a) { return a != 3; }),
conditional_end(source));
I suppose a conditional_end function would be necessary, since std::end would return a different iterator type than conditional_begin.
Maybe I have overlooked something, so my questions are:
Does the standard library provide something similar?
Is there a different easy way to achieve my goal?
Is there an easy way to implement the conditional iterator functionality?
Is there a different easy way to achieve my goal?
Yes, the standard already has this functionality built in. The function you are looking for is std::copy_if.
std::vector<int> source({1, 3, 2, 3, 4, 5, 3});
std::vector<int> target;
std::copy_if(source.begin(),
source.end(),
std::back_inserter(target), [](auto val){ return val != 3; });
Here, std::back_inserter(target), will call push_back on target for each element that the predicate returns true.
Yes, you can create a custom iterator that does what you want but it is currently a little tedious to create custom iterators using standard C++. It would look something like this:
template <typename Itr, typename F>
struct ConditionalIterator {
Itr itr;
Itr end;
F condition;
using value_type = typename Itr::value_type;
using difference_type = typename Itr::difference_type;
using pointer = typename Itr::pointer;
using reference = typename Itr::reference;
using iterator_category = std::forward_iterator_tag;
ConditionalIterator() = default;
ConditionalIterator(Itr itr, Itr end, F condition): itr(itr), end(end), condition(condition) {}
bool operator!=(const ConditionalIterator &other) const { return other.itr != itr; }
reference operator*() const { return *itr; }
pointer operator->() const { return &(*itr); }
ConditionalIterator& operator++() {
for (; ++itr != end;) {
if (condition(*itr))
break;
}
return *this;
}
ConditionalIterator operator++(int) {
ConditionalIterator ret(*this);
operator++();
return ret;
}
};
You can then create something like the conditional_begin and conditional_end helper functions you asked for. The only issue is that std::vector::insert expects the two iterators to have the same type. If we use a lambda for our condition then this will be part of the type of our conditional iterator. So we need to pass the lambda to both helper functions so that they return iterators with matching types:
template <typename C, typename F>
auto conditional_begin(const C &source, F f) {
return ConditionalIterator<typename C::const_iterator, F>(source.begin(),
source.end(), f);
}
template <typename C, typename F>
auto conditional_end(const C &source, F f) {
return ConditionalIterator<typename C::const_iterator, F>(source.end(),
source.end(), f);
}
Which you could call with a lambda like this:
auto condition = [](const auto &a) { return a != 3; };
target.insert(std::begin(target),
conditional_begin(source, std::ref(condition)),
conditional_end(source, std::ref(condition)));
Live demo.
My crude tests show, in this case, this ends up being significantly faster than simply using copy_if and back_inserter because std::vector::insert first works out how much memory to allocate before inserting. Just using back_inserter will cause multiple memory allocations. The difference in performance will depend on how expensive the condition is to evaluate. You can get the same speedup by using count_if to reserve enough space before using copy_if:
auto count = static_cast<size_t>(std::count_if(source.begin(),
source.end(), condition));
target.reserve(target.size() + count);
std::copy_if(source.begin(),
source.end(),
std::back_inserter(target), condition);
Live demo.
As ranges will be standardized soon, this is an alternative using range-v3, the reference library for the proprosal:
#include <range/v3/view/concat.hpp>
#include <range/v3/view/filter.hpp>
using namespace ranges;
const std::vector<int> source{1, 3, 2, 3, 4, 5, 3};
const std::vector<int> target = view::concat(source,
source | view::filter([](auto i){ return i != 3; }));
I got a (simplified) function Foo
template<typename It, typename T>
void Foo(It begin, It end, T&& CallBar)
{
CallBar(begin, end);
}
And another simplified function Bar
template<typename It>
It Bar(It begin, It end)
{
return begin;
}
When I call both functions in the following way
std::vector<int> v{ 3, 8, 2, 5, 1, 4, 7, 6 };
Foo(v.begin(), v.end(), Bar);
I get the error
'declaration' : could not deduce template argument for 'identifier'
What else do I have to specify to make it compile?
The issue here is that since Bar is a function template, it does not know which Bar you want. You have to tell it what version of Bar to use. One way to do that is by specifying the template type. You can do that like:
Foo(v.begin(), v.end(), Bar<decltype(v.begin())>);
If you would like to not have to specify the template type, which to be honest, is a little brittle then we can wrap the call to Bar in a lambda. This will allow the compiler to do all of the type deduction for us which is a lot easier to maintain. For example if you change the iterator type nothing you neede to be changed unlie the previous solution. Thanks to 0x499602D2 that would be
Foo(v.begin(),v.end(),[](auto b,auto e){return Bar(b,e);})
What else do I have to specify to make it compile?
By example
template<typename It>
void Foo(It begin, It end, It(* CallBar)(It, It))
{
CallBar(begin, end);
}
You can use template templates to help solve this. As far as I know, it requires you to wrap your Bar function in a functor. By placing the functor template parameter first, you can specify it and let the iterator type be deduced.
#include <vector>
// T is a type that takes a 'class' template argument
template<template<class> class T, class It>
void Foo(It begin, It end)
{
T<It>()(begin, end);
}
template<typename It>
struct Bar
{
It operator()(It begin, It end)
{
return begin;
}
};
int main()
{
std::vector<int> v{ 3, 8, 2, 5, 1, 4, 7, 6 };
Foo<Bar>(v.begin(), v.end());
return 0;
}
I have a vector of ints that I want to add multiple values too but too many values to add using a lot of push_backs. Is there any method of adding multiple values at the end of a vector. Something along the lines of this:
std::vector<int> values
values += {3, 9, 2, 5, 8, etc};
I found that boost has something like this, but I would like not having to include boost.
#include <boost/assign/std/vector.hpp>
using namespace boost::assign;
{
std::vector<int> myElements;
myElements += 1,2,3,4,5;
}
Which seems to be declared like this:
template <class V, class A, class V2>
inline list_inserter<assign_detail::call_push_back<std::vector<V,A> >, V>
operator+=( std::vector<V, A>& c, V2 v )
{
return push_back( c )( v );
}
Is there any C++/C++11 way to do this or, if not, how would it be implemented?
This should work:
std::vector<int> values;
values.insert( values.end(), { 1, 2, 3, 4 } );
Perhaps with insert:
values.insert( values.end(), {3, 9, 2, 5, 8, etc} );
Demo.
In order to present as much as possible solutions, this should work too:
for(const auto x : {11, 12, 13, 14})
v.push_back(x);
Demo.
You can just make an operator:
template <class T>
std::vector<T>& operator+=(std::vector<T>& lhs, std::initializer_list<T> l)
{
lhs.insert(std::end(lhs), l);
return lhs;
}
You can mimic the boost boost::assign behavior
template <typename T>
class vector_adder
{
public:
std::vector<T>& v;
vector_adder(std::vector<T>& v):v(v)
{ }
vector_adder& operator,(const T& val)
{
v.push_back(val);
return *this;
}
};
template <typename T>
vector_adder<T> operator+=(std::vector<T>& v,const T& x)
{
return vector_adder<T>(v),x;
}
Then,
std::vector<int> v {1,2,3,4};
v += 11,12,13,14 ;
See here
You can do it by using the insert member function, as such:
vector<int> v;
int myarr[] {1, 2, 4, 5, 5, 6, 6, 8}; //brace initialization with c++11
v.insert(v.end(), myarr, myarr+8);
There was a previous answer that omitted the middle argument in the insert parameters, but that one does not work. There are several formats to follow for the insert method, which can be found here and the code snippet I wrote practically follows this format:
vectorName.insert(postion to start entering values, first value to enter, how many values to enter)
Note: That the last two arguments (i.e. myarr, myarr+8) use pointer arithmetics. myarr is the address in memory of the first element in the array, and the second value is the address of the 8th element. You can read about pointer arithmetic here.
Hope that helps!