Here is my code:
#include <functional>
#include <iostream>
#include<vector>
using namespace std;
// vector iterator
template <class T> class vit
{
private:
//vector<T>::iterator it;
vector<T> m_v;
function<bool (T, T)> m_fptr;
int len, pos;
public:
vit(vector<T> &v) { this->m_v = v; len = v.size(); pos = 0;};
// it= v.begin(); };
bool next(T &i) {
//if(it == m_v.end()) return false;
if(pos==len) return false;
//i = *it;
i = m_v[pos];
//if(idle) { idle = false ; return true; }
//it++;
pos++;
return true;};
//bool idle = true;
void set_same(function<bool (T,T)> fptr) { m_fptr = fptr ;};
//void set_same(function<bool(int, int)> fun) { return ; }
bool grp_begin() {
return pos == 0 || ! m_fptr(m_v[pos], m_v[pos-1]); };
bool grp_end() {
return pos == len || ! m_fptr(m_v[pos], m_v[pos+1]); };
};
bool is_same(int a, int b) { return a == b; }
main()
{
vector<int> v ={ 1, 1, 2, 2, 2, 3, 1, 1, 1 };
int total;
for(auto it = v.begin(); it != v.end(); it++) {
if(it == v.begin() || *it != *(it-1)) {
total = 0;
}
total += *it;
if(it+1 == v.end() || *it != *(it+1)) {
cout << total << endl;
}
}
cout << "let's gry a group" <<endl;
vit<int> g(v);
int i;
while(g.next(i)) { cout << i << endl; }
cout << "now let's get really fancy" << endl;
vit<int> a_vit(v);
//auto is_same = [](int a, int b) { return a == b; };
a_vit.set_same(is_same);
//int total;
while(a_vit.next(i)) {
if(a_vit.grp_begin()) total = 0;
total += i;
if(a_vit.grp_end()) cout << total << endl ;
}
}
When I compile it with g++ -std=c++11 iter.cc -o iter, I get the result:
iter.cc: In function 'int main()':
iter.cc:63:17: error: reference to 'is_same' is ambiguous
a_vit.set_same(is_same);
^
iter.cc:37:6: note: candidates are: bool is_same(int, int)
bool is_same(int a, int b) { return a == b; }
^
In file included from /usr/include/c++/5.3.0/bits/move.h:57:0,
from /usr/include/c++/5.3.0/bits/stl_pair.h:59,
from /usr/include/c++/5.3.0/utility:70,
from /usr/include/c++/5.3.0/tuple:38,
from /usr/include/c++/5.3.0/functional:55,
from iter.cc:1:
/usr/include/c++/5.3.0/type_traits:958:12: note: template<class, class> struct std::is_same
struct is_same;
^
By way of explanation, I have created a class called 'vit'. It does two things: iterate over a vector, and determine if a new group has been reached.
The class function 'set_same' is supposed to store a function provided by the calling class to determine if two adjacent elements of a vector are in the same group. However, I can't seem to store the function in the class for future use by grp_begin() and grp_end() on account of the ostensible ambiguity of is_same.
What gives?
There is an is_same function defined by you and there is a struct is_same defined by the C++ Standard Library. Since you are using namespace std, your compiler doesn't know which is_same you meant to use.
It's what the error says: it's not clear whether you mean your is_same (in the global namespace) or the class template is_same (in namespace std).
You may disambiguate as follows:
::is_same
… with the leading :: meaning "in the global namespace".
Though you should consider putting your code in a namespace of its own.
Thanks guys. This is my first time touching C++ after more than a decade. I have cleaned up the code, and used a lambda to bring the "is_same" function closer to where it is called.
Did you spot the bug in my code? 'pos' was off-by-one when calling grp_begin() and grp_end(). Here is the revised code:
#include <functional>
#include <iostream>
#include <vector>
// vector iterator
template <class T> class vit
{
private:
std::vector<T> m_v;
std::function<bool (T, T)> m_fptr;
int len, pos;
public:
vit(std::vector<T> &v) { m_v = v; len = v.size(); pos = -1;};
bool next(T &val) {
pos++;
if(pos==len) return false;
val = m_v[pos];
return true;};
void set_same(std::function<bool (T,T)> fptr) { m_fptr = fptr ;};
bool grp_begin() {
return pos == 0 || ! m_fptr(m_v[pos], m_v[pos-1]); };
bool grp_end() {
return pos+1 == len || ! m_fptr(m_v[pos], m_v[pos+1]); };
};
main()
{
std::vector<int> v ={ 1, 1, 2, 2, 2, 3, 1, 1, 1 };
vit<int> a_vit(v);
std::function<bool (int, int)> is_same = [](int a, int b) { return a == b; };
a_vit.set_same(is_same);
int i, total;
while(a_vit.next(i)) {
if(a_vit.grp_begin()) total = 0;
total += i;
if(a_vit.grp_end()) std::cout << total << std::endl ;
}
}
My class definition isn't bullet-proof and could be better: if the user forgets to 'set-same', for example, they'll be referring a random memory address as a function.
Nevertheless, I'm pretty chuffed with my solution so far. The class caller is relieved of all the bookkeeping relating iterating over the vector, and working out if a group boundary has been crossed.
The calling code looks very compact and intuitive to me.I can see C++ being my go to language.
Related
I want to check whether an element exists in the vector or not. I know the below piece of code will check it.
#include <algorithm>
if ( std::find(vector.begin(), vector.end(), item) != vector.end() )
std::cout << "found";
else
std::cout << "not found";
But I have the vector of any type. i.e. std::vector<std::any>
I am pushing elements into vector like this.
std::vector<std::any> temp;
temp.emplace_back(std::string("A"));
temp.emplace_back(10);
temp.emplace_back(3.14f);
So I need to find whether string "A" present in the vector or not. Can std::find help here?
As of now I am using below piece of code to do this
bool isItemPresentInAnyVector(std::vector<std::any> items, std::any item)
{
for (const auto& it : items)
{
if (it.type() == typeid(std::string) && item.type() == typeid(std::string))
{
std::string strVecItem = std::any_cast<std::string>(it);
std::string strItem = std::any_cast<std::string>(item);
if (strVecItem.compare(strItem) == 0)
return true;
}
else if (it.type() == typeid(int) && item.type() == typeid(int))
{
int iVecItem = std::any_cast<int>(it);
int iItem = std::any_cast<int>(item);
if (iVecItem == iItem)
return true;
}
else if (it.type() == typeid(float) && item.type() == typeid(float))
{
float fVecItem = std::any_cast<float>(it);
float fItem = std::any_cast<float>(item);
if (fVecItem == fItem)
return true;
}
}
return false;
}
This should work good I guess:
#include <vector>
#include <string>
#include <any>
#include <algorithm>
#include <iostream>
int main(){
std::vector<std::any> temp;
temp.emplace_back(std::string("A"));
temp.emplace_back(10);
temp.emplace_back(3.14f);
int i = 10;//you can use any type for i variable and it should work fine
//std::string i = "A";
auto found = std::find_if(temp.begin(), temp.end(), [i](const auto &a){
return typeid(i) == a.type() && std::any_cast<decltype(i)>(a) == i;
} );
std::cout << std::any_cast<decltype(i)>(*found);
}
Or to make the code a bit more generic and reusable:
#include <vector>
#include <string>
#include <any>
#include <algorithm>
#include <iostream>
auto any_compare = [](const auto &i){
return [i] (const auto &val){
return typeid(i) == val.type() && std::any_cast<decltype(i)>(val) == i;
};
};
int main(){
std::vector<std::any> temp;
temp.emplace_back(std::string("A"));
temp.emplace_back(10);
temp.emplace_back(3.14f);
//int i = 10;
std::string i = "A";
auto found = std::find_if(temp.begin(), temp.end(), any_compare(i));
std::cout << std::any_cast<decltype(i)>(*found);
}
Live demo
Important note: this is guaranteed to work only within single translation unit due to stadard requirements on std::any type (for example same types don't need to have same type identifier in different translation units)
Using an any for this kind of purpose is not a good use of any. The best way to go is just to use a variant - since you have a closed set of types:
struct Equals {
template <typename T>
constexpr bool operator()(T const& a, T const& b) const { return a == b; }
template <typename T, typename U>
constexpr bool operator()(T const& a, U const& b) const { return false; }
};
using V = std::variant<int, float, std::string>
bool isItemPresentInAnyVector(std::vector<V> const& items, V const& item)
{
auto it = std::find_if(items.begin(), items.end(), [&](V const& elem){
return std::visit(Equals{}, elem, item);
});
return it != items.end();
}
Actually it's even better, because as Kilian points out, variant's operator== already works exactly like this:
using V = std::variant<int, float, std::string>
bool isItemPresentInAnyVector(std::vector<V> const& items, V const& item)
{
return std::find(items.begin(), items.end(), item) != items.end();
}
Unfortunately if you want to find an std::any instance in a vector of std::any instances the answer is no.
std::any does need some "magic" for example to be able to handle the creation of unknown object types but this machinery is private and must only supports object creation and not equality comparison.
It would be possible to implement what you are looking for using the same approach, but not with standard std::any that doesn't publish the needed details. The "manager" template needs to enumerate all possible operations and, for example, in g++ implementation they're "access", "get_type_info", "clone", "destroy", "xfer".
variant is completely different, because explicitly lists all the allowed types and therefore in any place it's used can access all the methods.
Comparison with typeId() should be avoided since it's dependent from translation unit.
A much safer approach can be used with any_cast of pointers:
template<typename T>
std::optional<T> find(const std::vector<std::any>& v)
{
for(auto&& e : v){
if(auto ptr = std::any_cast<T>(&e)){
return *ptr;
}
}
return std::nullopt;
}
Find first element with the given type, or nullopt if it's not found.
If we want to find all element with a specific instead:
template<typename T>
std::vector<T> findAll(const std::vector<std::any>& v)
{
std::vector<T> out;
for(auto&& e : v){
if(auto ptr = std::any_cast<T>(&e)){
out.push_back(*ptr);
}
}
return out;
}
Usage:
int main()
{
std::vector<std::any> temp;
temp.emplace_back(std::string("A"));
temp.emplace_back(10);
temp.emplace_back(3.14f);
temp.emplace_back(12);
temp.emplace_back(std::string("B"));
auto outInt = findAll<int>(temp);
std::cout << "out int: " << outInt.size() << std::endl;
for(auto&& out : outInt)
std::cout << out << std::endl;
auto outString = findAll<std::string>(temp);
std::cout << "out string: " << outString.size() << std::endl;
for(auto&& out : outString)
std::cout << out << std::endl;
auto singleInt = find<int>(temp);
if(singleInt)
std::cout << "first int " << *singleInt << std::endl;
auto singleBool = find<bool>(temp);
if(!singleBool)
std::cout << "ok: bool not found" << std::endl;
}
LIVE DEMO
If the types are int, float and string (or a limited set of types), you can use a combination of std::variant and std::get_if to achieve what you want to do in a simple manner:
std::get_if is to determine which of the types is stored in the std::variant.
A minimal example:
#include <iostream>
#include <vector>
#include <string>
#include <variant>
int main(){
std::vector<std::variant<int, float, std::string>> temp;
temp.emplace_back(std::string("A"));
temp.emplace_back(10);
temp.emplace_back(3.14f);
for (const auto& var: temp) {
if(std::get_if<std::string>(&var)) {
if(std::get<std::string>(var) == "A") std::cout << "found string\n";
}
if(std::get_if<int>(&var)) {
if(std::get<int>(var) == 10) std::cout << "found int\n";
}
if(std::get_if<float>(&var)) {
if(std::get<float>(var) == 3.14f) std::cout << "found float\n";
}
}
}
Live Demo
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
I want to use a single function to interact with multiple private member variables. I've come up with:
class Some_Vectors {
public:
int is_value_in_vector(string vector_name, int value);
void append_value_to_vector(string vector_name, int value)
private:
vector<int> A;
vector<int> B;
};
// returns value's index if it's there, -1 if not
int Some_Vectors::is_value_in_vector(string vector_name, int value) {
vector<int> *selected_vector;
if (vector_name == "A") {selected_vector = &A;}
else if (vector_name == "B") {selected_vector = &B;}
for (int i = 0; i < selected_vector->size(); i++){
if (selected_vector[0][i] == value){
return i;
}
}
return -1;
}
It works, but I feels unsafe/brittle to compare strings like that. Is there a way to specifically reference a private variable in the function call?
Edited to be a (hopefully) less subjective ask. I ended up using RichardCritten's suggestion of multiple public functions that call a single private function.
You can use the unordered_map to achieve your requirements as below.
Declare the unordered_map as below.
unordered_map<string, vector<int>> umap;
Insert the values to map by using [] operator.
umap["A"] = {10,20};
umap["B"] = {30,40};
Search the key value in the unordered_map as below using find function.
string vector_name = "A";
vector_name = "A";
auto it = umap.find(vector_name);
if (it == umap.end())
return -1;
Once you find the key,value pair in the map search the particular int in the vector as below.
std::vector<int>::iterator iter = std::find(it->second.begin(), it->second.end(), 20);
if iter is not pointing the vector end then return the exact position of the int in the vector as below.
if ( iter != it->second.end())
return std::distance(it->second.begin(),iter);
else
return -1;
Your complete sample code may look like below.
int main()
{
unordered_map<string, vector<int>> umap;
// inserting values by using [] operator
umap["A"] = {10,20};
umap["B"] = {30,40};
string vector_name = "A";
vector_name = "A";
auto it = umap.find(vector_name);
if (it == umap.end())
return -1;
std::vector<int>::iterator iter = std::find(it->second.begin(), it->second.end(), 20);
if ( iter != it->second.end())
return std::distance(it->second.begin(),iter);
else
return -1;
}
I have to disagree with the other answers that suggest maps or any kind of solutions involving strings.
Using strings to identify things in code is very fragile. Some major disadvantages are: no autocomplete, no compile-time checks. There are situations where you don't have a better alternative (e.g. you don't know the identifiers at compile time), but this is not one of them.
One solution is to give meaningful names to the functions. Since you provided a toy example I will use A and B but in real life they should be meaningful names:
class X
{
public:
auto foo_a(int value) { return foo(A, value); }
auto foo_b(int value) { return foo(B, value); }
private:
int foo(std::vector<int>& v, int value) { return 24; }
std::vector<int> A;
std::vector<int> B;
};
If you want one function with a parameter to select the vector, you should select the vector with an enum. This way you have autocomplete and compile-time safety (you can't pass an invalid selector - like you could with a string - unless you bend backwards):
class Y
{
public:
enum class Selector { A, B };
auto foo(Selector selector, int value) { return foo(getVector(selector), value); }
private:
std::vector<int>& getVector(Selector selector)
{
switch (selector)
{
case Selector::A:
return A;
case Selector::B:
return B;
}
}
int foo(std::vector<int>& v, int value) { return 24; }
std::vector<int> A;
std::vector<int> B;
};
Y y{};
y.foo(Y::Selector::A, 11);
y.foo(Y::Selector::B, 1024);
First of all, if you have access to C++17 or later versions of compilers the most modern and preferable way of optional return would be using std::optional.
Regarding your question, as #Dai mentioned in the comments, the best way would be(IMHO also) to use
std::unordered_map<std::string, std::vector</*type*/>>
as the member variable and you can do as follows. See Live here
#include <vector>
#include <string>
#include <unordered_map>
#include <iostream>
using uMapType = std::unordered_map<std::string, std::vector<int>>;
class MyClass
{
private:
uMapType _vecMap;
public:
explicit MyClass(const uMapType& vecMap): _vecMap(std::move(vecMap)) {}
int getValue(const std::string &vector_name, const int value)const
{
// std::unordered_map::find the key(vector name)
auto getVec = _vecMap.find(vector_name);
if(getVec != _vecMap.cend()) // if iterator not pointing to map's end
{
const std::vector<int> &selected_vector = getVec->second;
for (std::size_t i = 0; i < selected_vector.size(); ++i)
if (selected_vector[i] == value)
return i;
}
return -1;
}
};
int main()
{
MyClass obj(
{
{"A", {1, 2, 3, 4, 5}},
{"B", {1, 2, 3, 4, 5}}
});
std::cout << obj.getValue("A", 3) << std::endl; // output: 2
std::cout << obj.getValue("B", 5) << std::endl; // output: 5
std::cout << obj.getValue("C", 3) << std::endl; // output: -1
std::cout << obj.getValue("A", 0) << std::endl; // output: -1
return 0;
}
The std::optional sample solution will look like this.
#include <optional>
using uMapType = std::unordered_map<std::string, std::vector<int>>;
class MyClass
{
private:
uMapType _vecMap;
public:
explicit MyClass(const uMapType& vecMap): _vecMap(std::move(vecMap)) {}
std::optional<int> getValue(const std::string &vector_name, const int value)const
{
if(auto getVec = _vecMap.find(vector_name); getVec != _vecMap.cend())
{
for (std::size_t i = 0; i < getVec->second.size(); ++i)
if (getVec->second[i] == value)
return i;
}
return std::nullopt;
}
};
I have this problem I'm trying to solve. Basically the base class has the function map, which takes a vector as input and outputs the final vector after some mapping function, in this case - f, has been performed. However, I'm really lost as to why when I print out 2*testVector - test1 in the main function, I get proper output, i.e. 6, -182 etc... but when I print out 2*testVector - test 2, it's still the same vector.
This happens both when I create "DoubleElements" twice or just call the same "DoubleElements" pointer twice (it only ever performs 1 map). Am I fundamentally missing some understanding? Any help is appreciated!
#include <iostream>
#include <vector>
using namespace std;
class RecursiveBase {
public:
vector<int> map(vector<int> baseVector) {
static int iter = 0;
// Base case, return the final vector.
if (iter == 5) {
return baseVector;
// Replace the element with the old element mapped to the function.
} else {
baseVector[iter] = this->f(baseVector[iter]);
iter++;
return map(baseVector);
}
}
private:
virtual int f(int value) = 0;
};
class DoubleElements: public RecursiveBase {
private:
int f(int value) {
return 3*value;
}
};
int main() {
vector<int> testVector, o1, o2;
testVector.push_back(3);
testVector.push_back(-91);
testVector.push_back(-42);
testVector.push_back(-16);
testVector.push_back(13);
DoubleElements de;
DoubleElements de1;
RecursiveBase *test1 = &de;
RecursiveBase *test2 = &de1;
o1 = test1->map(testVector);
o2 = test2->map(testVector);
std::cout << "2*testVector - test1" << std::endl;
for (unsigned int iter = 0; iter < o1.size(); iter++) {
std::cout << o1[iter] << std::endl;
}
std::cout << "2*testVector - test2" << std::endl;
for (unsigned int iter = 0; iter < o2.size(); iter++) {
std::cout << o2[iter] << std::endl;
}
}
static int iter = 0;
You should avoid declaring local static variables in methods unless 100% necessary.
The first call will increment iter to 5, but on the next call, iter, since it's static, will not reset it's value to 0.
As an example, a simple program like:
void test()
{
static int x = 0;
++x;
cout << x << endl;
}
int main()
{
test();
test();
return 0;
}
Will output
1
2
From class.static.data/1:
A static data member is not part of the subobjects of a class.
For iter is static. It is part of the class RecursiveBase NOT part of the RecursiveBase objects.
To fix it, reset iter to 0:
if (iter == 5) {
iter = 0; // reset iter
return baseVector;
}
OUTPUT
2*testVector - test1
9
-273
-126
-48
39
2*testVector - test2
9
-273
-126
-48
39
You can only ever call RecursiveBase::map once as it stands, because the iter is static. You also assume that you will only ever call it with a 5 element std::vector<int>, at which point std::array<int, 5> is a better choice.
If you want a recursive solution, instead pass the index as an additional parameter
public:
std::vector<int> map(std::vector<int> vec) {
return do_map(vec, 0);
}
private:
std::vector<int> do_map(std::vector<int> & vec, std::size_t index) {
if (index == vec.size()) { return vec; }
vec[index] = f(vec[index]);
return do_map(vec, ++index);
}
But that's still a gratuitous use of recursion. A much better solution is
public:
std::vector<int> map(std::vector<int> vec) {
std::transform(vec.begin(), vec.end(), vec.begin(), [this](int i) { return f(i); });
return vec;
}
You also have superfluous RecursiveBase * in your main
int main() {
std::vector<int> testVector{3, -91, -42, -16, 13};
DoubleElements de;
DoubleElements de1;
// declare at point of initialisation
// don't need ->
auto o1 = de.map(testVector);
auto o2 = de1.map(testVector);
std::cout << "2*testVector - test1" << std::endl;
for (unsigned int iter = 0; iter < o1.size(); iter++) {
std::cout << o1[iter] << std::endl;
}
std::cout << "2*testVector - test2" << std::endl;
for (unsigned int iter = 0; iter < o2.size(); iter++) {
std::cout << o2[iter] << std::endl;
}
return 0;
}
How to implement an iterator of just on values of a map/unordered_map using boost::iterator_adaptor? I've tried following code but it does not work because of the line with comment.
Is there a solution to avoid the problem?
The question here is slightly different from map_values adapter example shown in boost code as here the value field in map is another container like list or vector and the requirement here is to iterate over all elements of those lists for every key of the map.
The deref of iterator is of type of value_type of those list/vector.The end of iterator is the end of list of last key
#include <vector>
#include <boost/unordered_map.hpp>
#include <cassert>
#include <iostream>
#include <boost/iterator/iterator_adaptor.hpp>
class DS {
public:
DS() : _map() {}
~DS() {
for (Map::iterator it = _map.begin(); it != _map.end(); ++it) {
delete (it->second);
}
}
void add(int key_, const std::vector< int > &value_)
{
IntList *ptr = new IntList(value_);
assert(ptr);
_map.insert(Map::value_type(key_, ptr));
}
private:
typedef std::vector< int > IntList;
typedef boost::unordered_map< int, IntList* > Map;
Map _map;
public:
class KeyIter : public boost::iterator_adaptor< KeyIter,
Map::const_iterator,
int,
boost::forward_traversal_tag,
int>
{
public:
KeyIter() : KeyIter::iterator_adaptor_() {}
private:
friend class DS;
friend class boost::iterator_core_access;
explicit KeyIter(Map::const_iterator it) : KeyIter::iterator_adaptor_(it) {}
explicit KeyIter(Map::iterator it) : KeyIter::iterator_adaptor_(it) {}
int dereference() const { return this->base()->first; }
};
class ValueIter : public boost::iterator_adaptor< ValueIter,
Map::const_iterator,
int,
boost::forward_traversal_tag,
int>
{
public:
ValueIter()
: ValueIter::iterator_adaptor_()
, _lIt()
{}
private:
friend class DS;
friend class boost::iterator_core_access;
explicit ValueIter(Map::const_iterator it)
: ValueIter::iterator_adaptor_(it)
, _lIt()
, _mIt(it)
{
IntList *pt = it->second; // <<-- issue here is I can't find if I've already reached the end of the map
if (pt) {
_lIt = it->second->begin();
}
}
int dereference() const { return *_lIt; }
void increment()
{
if (_lIt == _mIt->second->end()) {
++_mIt;
_lIt = _mIt->second->begin();
} else {
++_lIt;
}
}
IntList::iterator _lIt;
Map::const_iterator _mIt;
};
KeyIter beginKey() const { return KeyIter(_map.begin()); }
KeyIter endKey() const { return KeyIter(_map.end()); }
ValueIter beginValue() const { return ValueIter(_map.begin()); }
ValueIter endValue() const { return ValueIter(_map.end()); }
};
int main(int argc, char** argv)
{
DS ds;
std::vector< int > v1;
v1.push_back(10);
v1.push_back(30);
v1.push_back(50);
ds.add(90, v1);
std::vector< int > v2;
v2.push_back(20);
v2.push_back(40);
v2.push_back(60);
ds.add(120, v2);
std::cout << "------------ keys ---------------" << std::endl;
for (DS::KeyIter it = ds.beginKey(); it != ds.endKey(); ++it) {
std::cout << (*it) << std::endl;
}
std::cout << "------------ values ---------------" << std::endl;
// std::cout << (*(ds.beginValue())) << std::endl;
for (DS::ValueIter it = ds.beginValue(); it != ds.endValue(); ++it) {
std::cout << (*it) << std::endl;
}
return 0;
}
Implemented in c++11. You should be able to do the conversion to boost/c++03 fairly simply.
This iterator is FORWARD ONLY and it's quite fragile (see the comparison operator).
user discretion advised.
#include <iostream>
#include <vector>
#include <unordered_map>
typedef std::vector< int > IntList;
typedef std::unordered_map< int, IntList* > Map;
struct whole_map_const_iterator
{
using C1 = IntList;
using C2 = Map;
using I1 = C1::const_iterator;
using I2 = C2::const_iterator;
using value_type = I1::value_type;
using reference = I1::reference;
whole_map_const_iterator(I2 i2) : _i2(i2) {}
bool operator==(const whole_map_const_iterator& r) const {
if (_i2 != r._i2)
return false;
if (deferred_i1 && r.deferred_i1)
return true;
if (deferred_i1 != r.deferred_i1)
return false;
return _i1 == r._i1;
}
bool operator!=(const whole_map_const_iterator& r) const { return !(*this == r); }
reference operator*() const {
check_deferred();
return *_i1;
}
void check_deferred() const {
if (deferred_i1) {
_i1 = _i2->second->begin();
_i1limit = _i2->second->end();
deferred_i1 = false;
}
}
void go_next()
{
check_deferred();
if (++_i1 == _i1limit) {
++_i2;
deferred_i1 = true;
}
}
whole_map_const_iterator& operator++() {
go_next();
return *this;
}
whole_map_const_iterator operator++(int) {
auto result = *this;
go_next();
return result;
}
I2 _i2;
mutable I1 _i1 = {}, _i1limit = {};
mutable bool deferred_i1 = true;
};
IntList a { 1, 2, 3, 4, 5 };
IntList b { 6, 7, 8, 9, 10 };
Map m { { 1, &a }, { 2, &b } };
int main()
{
using namespace std;
auto from = whole_map_const_iterator(m.begin());
auto to = whole_map_const_iterator(m.end());
for ( ; from != to ; ++from) {
std::cout << *from << std::endl;
}
return 0;
}
example output:
6
7
8
9
10
1
2
3
4
5
For bonus points, answer this question:
Q: Why all that damn complication over the deferred flag?
I'm coding in C++, and I have the following code:
int array[30];
array[9] = 1;
array[5] = 1;
array[14] = 1;
array[8] = 2;
array[15] = 2;
array[23] = 2;
array[12] = 2;
//...
Is there a way to initialize the array similar to the following?
int array[30];
array[9,5,14] = 1;
array[8,15,23,12] = 2;
//...
Note: In the actual code, there can be up to 30 slots that need to be set to one value.
This function will help make it less painful.
void initialize(int * arr, std::initializer_list<std::size_t> list, int value) {
for (auto i : list) {
arr[i] = value;
}
}
Call it like this.
initialize(array,{9,5,14},2);
A variant of aaronman's answer:
template <typename T>
void initialize(T array[], const T& value)
{
}
template <size_t index, size_t... indices, typename T>
void initialize(T array[], const T& value)
{
array[index] = value;
initialize<indices...>(array, value);
}
int main()
{
int array[10];
initialize<0,3,6>(array, 99);
std::cout << array[0] << " " << array[3] << " " << array[6] << std::endl;
}
Example: Click here
Just for the fun of it I created a somewhat different approach which needs a bit of infrastructure allowing initialization like so:
double array[40] = {};
"9 5 14"_idx(array) = 1;
"8 15 23 12"_idx(array) = 2;
If the digits need to be separated by commas, there is a small change needed. In any case, here is the complete code:
#include <algorithm>
#include <iostream>
#include <sstream>
#include <iterator>
template <int Size, typename T = int>
class assign
{
int d_indices[Size];
int* d_end;
T* d_array;
void operator=(assign const&) = delete;
public:
assign(char const* base, std::size_t n)
: d_end(std::copy(std::istream_iterator<int>(
std::istringstream(std::string(base, n)) >> std::skipws),
std::istream_iterator<int>(), this->d_indices))
, d_array()
{
}
assign(assign<Size>* as, T* a)
: d_end(std::copy(as->begin(), as->end(), this->d_indices))
, d_array(a) {
}
assign(assign const& o)
: d_end(std::copy(o.begin(), o.end(), this->d_indices))
, d_array(o.d_array)
{
}
int const* begin() const { return this->d_indices; }
int const* end() const { return this->d_end; }
template <typename A>
assign<Size, A> operator()(A* array) {
return assign<Size, A>(this, array);
}
void operator=(T const& value) {
for (auto it(this->begin()), end(this->end()); it != end; ++it) {
d_array[*it] = value;
}
}
};
assign<30> operator""_idx(char const* base, std::size_t n)
{
return assign<30>(base, n);
}
int main()
{
double array[40] = {};
"1 3 5"_idx(array) = 17;
"4 18 7"_idx(array) = 19;
std::copy(std::begin(array), std::end(array),
std::ostream_iterator<double>(std::cout, " "));
std::cout << "\n";
}
I just had a play around for the sake of fun / experimentation (Note my concerns at the bottom of the answer):
It's used like this:
smartAssign(array)[0][8] = 1;
smartAssign(array)[1][4][2] = 2;
smartAssign(array)[3] = 3;
smartAssign(array)[5][9][6][7] = 4;
Source code:
#include <assert.h> //Needed to test variables
#include <iostream>
#include <cstddef>
template <class ArrayPtr, class Value>
class SmartAssign
{
ArrayPtr m_array;
public:
class Proxy
{
ArrayPtr m_array;
size_t m_index;
Proxy* m_prev;
Proxy(ArrayPtr array, size_t index)
: m_array(array)
, m_index(index)
, m_prev(nullptr)
{ }
Proxy(Proxy* prev, size_t index)
: m_array(prev->m_array)
, m_index(index)
, m_prev(prev)
{ }
void assign(Value value)
{
m_array[m_index] = value;
for (auto prev = m_prev; prev; prev = prev->m_prev) {
m_array[prev->m_index] = value;
}
}
public:
void operator=(Value value)
{
assign(value);
}
Proxy operator[](size_t index)
{
return Proxy{this, index};
}
friend class SmartAssign;
};
SmartAssign(ArrayPtr array)
: m_array(array)
{
}
Proxy operator[](size_t index)
{
return Proxy{m_array, index};
}
};
template <class T>
SmartAssign<T*, T> smartAssign(T* array)
{
return SmartAssign<T*, T>(array);
}
int main()
{
int array[10];
smartAssign(array)[0][8] = 1;
smartAssign(array)[1][4][2] = 2;
smartAssign(array)[3] = 3;
smartAssign(array)[5][9][6][7] = 4;
for (auto i : array) {
std::cout << i << "\n";
}
//Now to test the variables
assert(array[0] == 1 && array[8] == 1);
assert(array[1] == 2 && array[4] == 2 && array[2] == 2);
assert(array[3] == 3);
assert(array[5] == 4 && array[9] == 4 && array[6] == 4 && array[7] == 4);
}
Let me know what you think, I don't typically write much code like this, I'm sure someone will point out some problems somewhere ;)
I'm not a 100% certain of the lifetime of the proxy objects.
The best you can do if your indexes are unrelated is "chaining" the assignments:
array[9] = array[5] = array[14] = 1;
However if you have some way to compute your indexes in a deterministic way you could use a loop:
for (size_t i = 0; i < 3; ++i)
array[transform_into_index(i)] = 1;
This last example also obviously applies if you have some container where your indexes are stored. So you could well do something like this:
const std::vector<size_t> indexes = { 9, 5, 14 };
for (auto i: indexes)
array[i] = 1;
Compilers which still doesn't support variadic template argument and universal initialization list, it can be a pain to realize, that some of the posted solution will not work
As it seems, OP only intends to work with arrays of numbers, valarray with variable arguments can actually solve this problem quite easily.
#include <valarray>
#include <cstdarg>
#include <iostream>
#include <algorithm>
#include <iterator>
template <std::size_t size >
std::valarray<std::size_t> selection( ... )
{
va_list arguments;
std::valarray<std::size_t> sel(size);
//Skip the first element
va_start ( arguments, size );
va_arg ( arguments, int );
for(auto &elem : sel)
elem = va_arg ( arguments, int );
va_end ( arguments );
return sel;
}
int main ()
{
//Create an array of 30 integers
std::valarray<int> array(30);
//The first argument is the count of indexes
//followed by the indexes of the array to initialize
array[selection<3>(9,5,14)] = 1;
array[selection<4>(8,15,13, 12)] = 2;
std::copy(std::begin(array), std::end(array),
std::ostream_iterator<int>(std::cout, " "));
return 0;
}
I remember, for static initialization exist syntax like:
int array[30] = {
[9] = 1, [8] = 2
}
And so on. This works in gcc, about another compilers - I do not know.
Use overload operator << .
#include <iostream>
#include <iomanip>
#include <cmath>
// value and indexes wrapper
template< typename T, std::size_t ... Ints> struct _s{ T value; };
//deduced value type
template< std::size_t ... Ints, typename T>
constexpr inline _s<T, Ints... > _ ( T const& v )noexcept { return {v}; }
// stored array reference
template< typename T, std::size_t N>
struct _ref
{
using array_ref = T (&)[N];
array_ref ref;
};
//join _s and _ref with << operator.
template<
template< typename , std::size_t ... > class IC,
typename U, std::size_t N, std::size_t ... indexes
>
constexpr _ref<U,N> operator << (_ref<U,N> r, IC<U, indexes...> ic ) noexcept
{
using list = bool[];
return ( (void)list{ false, ( (void)(r.ref[indexes] = ic.value), false) ... }) , r ;
//return r;
}
//helper function, for creating _ref<T,N> from array.
template< typename T, std::size_t N>
constexpr inline _ref<T,N> _i(T (&array)[N] ) noexcept { return {array}; }
int main()
{
int a[15] = {0};
_i(a) << _<0,3,4,5>(7) << _<8,9, 14>( 6 ) ;
for(auto x : a)std::cout << x << " " ;
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
//result: 7 0 0 7 7 7 0 0 6 6 0 0 0 0 6
double b[101]{0};
_i(b) << _<0,10,20,30,40,50,60,70,80,90>(3.14)
<< _<11,21,22,23,24,25>(2.71)
<< _<5,15,25,45,95>(1.414) ;
}
struct _i_t
{
int * array;
struct s
{
int* array;
std::initializer_list<int> l;
s const& operator = (int value) const noexcept
{
for(auto i : l )
array[i] = value;
return *this;
}
};
s operator []( std::initializer_list<int> i ) const noexcept
{
return s{array, i};
}
};
template< std::size_t N>
constexpr _i_t _i( int(&array)[N]) noexcept { return {array}; }
int main()
{
int a[15] = {0};
_i(a)[{1,3,5,7,9}] = 7;
for(auto x : a)std::cout << x << ' ';
}
Any fancy trickery you do will be unrolled by the compiler/assembler into exactly what you have. Are you doing this for readability reasons? If your array is already init, you can do:
array[8] = array[15] = array[23] = array[12] = 2;
But I stress my point above; it will be transformed into exactly what you have.