0

I am new to STL maps and vector. I am trying to print the elements present inside the set of vector. The last for-loops are used for printing the elements. The code is given below :

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
    int arr[]={2,0,2,1,4,3,1,0};

    vector<int> v;
    set< vector<int> > st;
    //set<int> temp;
    int init=0,fin=0;
    for(int i=0;i<8;++i){
        if(find(v.begin(),v.end(),arr[i])==v.end()){//if(temp.find(arr[i])==temp.end()){
            v.push_back(arr[i]);//temp.insert(arr[i]);

        }
        else{
            st.insert(v);
            v.clear();//temp.clear();
            v.push_back(arr[i]);//temp.insert(arr[i]);
        }

    }
    set<vector<int> >::iterator itr;
    vector<int>::iterator str;
    for(itr=st.begin();itr!=st.end();++itr){
        for(str=itr->begin();str!=itr->end();++str){
            cout<<*str<<" ";
        }
        cout<<endl;
    }
    return 0;

}

The error is:

a.cpp:26:11: error: no viable overloaded '='
                        for(str=itr->begin();str!=itr->end();++str){
                            ~~~^~~~~~~~~~~~~
/Library/Developer/CommandLineTools/usr/include/c++/v1/iterator:1258:7: note: candidate function (the implicit copy assignment operator) not viable: no known conversion from '__wrap_iter<const_pointer>'
      to 'const __wrap_iter<int *>' for 1st argument
class __wrap_iter
      ^
a.cpp:34:2: error: unknown type name 'a'
        a.cpp:26:10: error: no viable overloaded '='
        ^
a.cpp:34:3: error: cannot use dot operator on a type
        a.cpp:26:10: error: no viable overloaded '='
asn
  • 2,408
  • 5
  • 23
  • 37
  • 6
    Sites that preach `using namespace std;` and particularly the `typedef long long ll;` and `#include` are the sites that should be avoided. – Ron Jul 24 '18 at 11:41
  • I agree.But, if you compete in competitive programming then this becomes short and concise. Although, these may incur some errors. – asn Jul 24 '18 at 11:44
  • 4
    Arguably those are just a waste of time. Read these [C++ books](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) instead. Much better return on investment. – Ron Jul 24 '18 at 11:45
  • How is it a waste of time when you have to just write a single line of code for the header and just write ll instead of long long int. – asn Jul 24 '18 at 11:47
  • 4
    Look up "range based for loop". – Jesper Juhl Jul 24 '18 at 11:47
  • 4
    @Jacob Because it teaches you nothing. And what it does teach, does so in a wrong manner. There is no such thing as a _competitive programming_. – Ron Jul 24 '18 at 11:48
  • 4
    @Jacob It's a waste of time since saving a few keystrokes is completely irrelevant - typing is not where time is spent when writing code - thinking is. And you loose readability - which is *much more* important. – Jesper Juhl Jul 24 '18 at 11:50
  • 1
    @Jacob if you care so much about short and concise code, then why are you explicitly spelling out iterator types and doing everything with three times the code that is actually necessary? – Tim Seguine Jul 24 '18 at 11:51
  • I agree with you but when you know sth. then why not to use shortcuts. – asn Jul 24 '18 at 11:51
  • 1
    @Jacob "why not to use shortcuts" - because it is *not* more efficient and it makes your code unreadable to other humans (the compiler doesn't care, it'll generate the same code regardless of your "shortcuts"). – Jesper Juhl Jul 24 '18 at 11:55
  • Yes. Well, it slows down compilation. But, how does it make the code less readable ? – asn Jul 24 '18 at 11:56
  • @Jacob slows down compilation? Citation needed. There are many C++ techniques that slow down compilation. You aren't using any of them. If you want to know how it makes code less readable, just wait 6 months and then try to fix a bug in a program you wrote. – Tim Seguine Jul 24 '18 at 11:59
  • 1
    @Jacob It's less readable because - for example - everyone knows what `long long` is, but noone knows what `ll` is, so everyone reading the code will have to go look up the definition of `ll` and remember it (and that knowledge is *only* useful while reading *your* code. In some other project `ll` might have a different definition). Using the common vocabulary makes it easier for people to read your code since you use terms people *already* know. – Jesper Juhl Jul 24 '18 at 12:01
  • That's what I am saying. As long as you know that you are going to use the above code snippets in your own programs, then that's alright. But for a project, it's not good and a source of confusion. – asn Jul 24 '18 at 12:04
  • 1
    @Jacob that is *extremely* naive – Tim Seguine Jul 24 '18 at 12:06
  • @TimSeguine I'm talking about the header taking longer compilation time and not the "typedef long long int ll" – asn Jul 24 '18 at 12:06
  • 3
    @Jacob I work on build systems as my day job. What you are doing is technically slower actually. But that wasn't my point. You are not using language features which are slow to compile(trust me, I do template metaprogramming for fun). And you are including the entire standard library to try to paradoxically improve compilation speed. We're trying to tell you nicely that whatever you read that told you these things was wrong, and you have been misled. – Tim Seguine Jul 24 '18 at 12:11
  • Just to be clear: the use case for "#include" is subtle, and requires a specific scenario to be faster (large projects and precompiled headers), and in my testing you almost always lose everything you gain in parsing speed on increased link times. – Tim Seguine Jul 24 '18 at 12:24
  • @TimSeguine You said " There are many C++ techniques that slow down compilation. You aren't using any of them." . I hoped that bits/stdc++.h makes the compilation slow. – asn Jul 24 '18 at 12:24
  • @Jacob Are you a chatbot? I have been using C++ since the 90s and you are literally the first person I have ever heard claim their C++ compiler was too fast. – Tim Seguine Jul 24 '18 at 12:32
  • More slow, I mean – asn Jul 24 '18 at 12:34
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/176648/discussion-between-tim-seguine-and-jacob). – Tim Seguine Jul 24 '18 at 12:35

2 Answers2

2

Your str iterator needs to be const because it is not possible to mutate the elements of the set.

vector<int>::const_iterator str;

I'm not the biggest fan of auto, but this is one occasion where if you use it, you don't need to know what the iterator type is

for (auto str = itr->begin(); str != itr->end(); ++str)
acraig5075
  • 10,588
  • 3
  • 31
  • 50
  • Why ? How do I know when to use const and when not to ? – asn Jul 24 '18 at 11:45
  • 3
    @Jacob : [`std::set` iterators are constant iterators](https://en.cppreference.com/w/cpp/container/set/begin), and can thus not be used to mutate the elements. – Sander De Dycker Jul 24 '18 at 11:47
  • Don't you mean `for (auto str = itr->cbegin(); ...` ? – Jesper Juhl Jul 24 '18 at 11:52
  • It says that it returns iterator as well as const_iterator. How do you know which one does it return ? Also, is this true for other STL containers ? – asn Jul 24 '18 at 11:53
  • 2
    @Jacob : read the **Notes** section in the link I posted. And no, this is not true for all containers - a `std::set` is just special in that the value is also the key (for ordering), so it cannot be modified. – Sander De Dycker Jul 24 '18 at 11:58
  • So, that means that I cannot change the set elements through iterators. But, how do I change a set element the other way ? – asn Jul 24 '18 at 12:07
  • 1
    @Jacob erase the original and insert the new. It is only through `insert` that you get the knowledge of whether the set already contained the element. – acraig5075 Jul 24 '18 at 12:10
  • 1
    @Jacob : you can't (unless you use `mutable`). Maybe what you need is a different container - eg. `std::map`. – Sander De Dycker Jul 24 '18 at 12:11
  • @acraig5075 Now that set iterators are const. why am I making "str" as const and not "itr" as const. – asn Jul 24 '18 at 12:41
  • @Jacob You can make `itr` a const_iterator too, and this would probably be good practise and make your intention clear. But you don't have to, unlike `str` which has to be because of the uniqueness and non-mutability of a set. – acraig5075 Jul 24 '18 at 12:53
  • @acraig5075 I mean why are we making "str" as const because it is iterating over the vector elements present inside set. Here, itr is a set iterator which is iterating over the vectors present inside the set. So, in that sense "itr" should have been made const – asn Jul 25 '18 at 12:13
2

If your compiler is C++ 11 compliant, instead of set<vector<int> >::iterator itr;..., try this - it is much cleaner:

  for ( const auto& v : st )
    for ( const auto& i : v )
      cout << i << " ";

Read here about auto and here about rage-for.

[Edit]

"So, does that make the elements as const for the time being inside the loop and not later?"

The set element is constant at any time, otherwise the uniqueness will not hold.

* operator of a set iterator is defined as a function returning a constant reference to iterator's current element; this is why you cannot modify the element. And it is protected in this way for otherwise the uniqueness constraint cannot be guarantee.

Take set {1, 2, 3} and imagine you are changing 1 to 2. The resulting set, {2, 2, 3} is no longer a set for 2 is not unique.

Instead, if you first remove the element {1, 2, 3} - {1} = {2, 3} and then you try to insert the modified element {2, 3} + {2}, you will end with a correct set: {2, 3} for 2 is not inserted since it is already present.

zdf
  • 4,382
  • 3
  • 18
  • 29
  • Is const necessary here ? What if I remove it ? – asn Jul 24 '18 at 12:09
  • @Jacob _"`set` is an associative container that contains a sorted set of unique objects of type Key"_ How can one change an element of a set and guarantee the uniqueness at the same time? The correct way is: remove the element and try to reinsert the modified element. After all the purpose of a `set` is uniqueness. – zdf Jul 24 '18 at 12:17
  • @Jacob Are you trying to learn how to program or how to play code golf? The principle of least privilege implies everything should be const unless you need to mutate it. – Tim Seguine Jul 24 '18 at 12:28
  • 2
    @Jacob If you remove `const`, nothing will happen. It is just a habit: _"I have no intention to modify `v` or `i`"_. You will still not be able to change the element since the type of `v` and `i` iterators is const iterator. Maybe you are confused about `const` objects and `const_iterator`s. A constant object cannot be modified, but const iterators are not constant objects: **they are iterators to constant objects**. – zdf Jul 24 '18 at 12:37
  • So, does that make the elements as const for the time being inside the loop and not later ? – asn Jul 24 '18 at 12:47
  • You get const references bound to the objects. The underlying objects are unchanged – Caleth Jul 24 '18 at 12:51
  • You didn't get my point. I mean, when you use const_iterator to point to the element, does that mean that you can't change the elements only through iterators while other ways of change(excluding set) are easy to be performed. I hope you are mentioning uniqueness only with respect to the set elements but what about the other containers. – asn Jul 24 '18 at 13:24
  • @Jacob We're talking about `set`. – zdf Jul 24 '18 at 13:26
  • @Jacob I'm not sure I understand what you do not understand. `const_iterator` means iterator to constant references, regardless of container type. The following will fail for the iterator returns a constant reference: `vector::const_iterator i { v.begin() }; *i = 2;` – zdf Jul 24 '18 at 13:54