Thread: const qualifiers cannot be applied to '&'

  1. #1
    ...and never returned. StainedBlue's Avatar
    Join Date
    Aug 2009
    Posts
    168

    const qualifiers cannot be applied to '&'

    Code:
    #include <list>
    
    template
    <
        typename T
    >
    class Foo
    {
        T container;
    
        typedef typename T::iterator iterator;
    
        struct Bar
        {
            typedef decltype(*container.begin()) T_type;
            T_type t;
    
            iterator* index;
    
            Bar
            (   const T_type& t,
                iterator* index = 0
            ) : t(t),
                index(index)
            {   }
        };
    
        std::list<Bar> bars;
    
        public:
    
            Foo<T>(const T& src);
    };
    
    template
    <
        typename T
    >
    Foo<T>::Foo(const T& src)
    {
        typename T::const_iterator it = src.begin(), end = src.end();
        for( ; it != end; ++it )
        {
            Bar b(*it);
            bars.push_back(b);
        }
    }
    
    class test{   };
    
    int main()
    {
        std::list<test> list;
        Foo<std::list<test>> foo(list);
    
        return 0;
    }

    I'm trying to copy the elements of the container into wrapper objects, but I keep getting the error:

    Code:
    error: 'const' qualifiers cannot be applied to 'test&'|
    Removing const from the constructor arguments (and the reference to T_type t in Bar's constructor) allows me to compile, but I don't like the idea of providing an interface that doesn't guarantee the user's original container won't be modified.
    Last edited by StainedBlue; 06-03-2010 at 07:33 PM.
    goto( comeFrom() );

  2. #2
    ...and never returned. StainedBlue's Avatar
    Join Date
    Aug 2009
    Posts
    168
    In case anyone is wondering about the iterator pointer...

    I know multi-indexing can be achieved in simpler ways, such as a map of Key, Object*. However, that requires an additional search (via the find method) to obtain an iterator to the desired location.

    I'm trying to avoid the extra lookups. This is the basis of my idea:

    Code:
    #include <iostream>
    #include <algorithm>
    #include <list>
    
    bool base_sort(int a, int b)
    {
        return a > b; // stupid, but for demonstration
    }
    
    void display(int i)
    {
        std::cout << i << "\n";
    }
    
    int main()
    {
        std::list<int> base;
        std::list<std::list<int>::iterator> base_iterators;
    
        for(int i = 0; i < 10; i++)
        {
            base.push_back(i);
        }
    
        std::list<int>::iterator it = base.begin();
        for(; it != base.end(); it++)
        {
            base_iterators.push_back(it);
        }
    
        std::list<int>::iterator* it_ptr = &base.begin();
        std::cout << "Beginning: " << **it_ptr << "\n\n";
    
        std::for_each(base.begin(), base.end(), display );
    
        base.sort(&base_sort);
    
        std::cout << "\nEnd: " << **it_ptr << "\n\n";
        std::for_each(base.begin(), base.end(), display );
    
        std::cout << "\nIterating backwards from the end:\n\n";
        std::list<int>::iterator it_copy = *it_ptr;
        for(int i = 0; i < 3; i++)
        {
            std::cout << *it_copy << "\n";
            it_copy--;
        }
    
        return 0;
    }

    I want to take advantage of how iterators are really pointers underneath it all. If i sort the list, the iterators go with the elements they point to. And so if the wrapper objects contain the original container values, plus an added iterator pointer, i should be able to achieve O(1) efficiency of getting an iterator into any of the projected containers, at the desired location. That's the idea anyway.
    Last edited by StainedBlue; 06-03-2010 at 08:35 PM.
    goto( comeFrom() );

  3. #3
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    I made it compile by changing this:

    Code:
    typedef decltype(*container.begin()) T_type;
    To this:

    Code:
    typedef typename T::iterator::value_type T_type;
    Which is probably more correct anyway. To be even more general, you'd use iterator traits instead. But that declspec() thing made me gag. I know it's a C++0x thing but in this case I don't see why you even need it.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  4. #4
    ...and never returned. StainedBlue's Avatar
    Join Date
    Aug 2009
    Posts
    168
    Quote Originally Posted by brewbuck View Post
    But that declspec() thing made me gag.
    It's late, I've been up way too long, and now thanks to you, I can't stop laughing!

    decltype was suggested to me in another thread for obtaining the type, which seems legit considering enough hits on google are calling value_type deprecated. Oh well, since I'm in no position to argue one way or the other over it, i'll just go with what compiles.

    Thanks
    goto( comeFrom() );

  5. #5
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Well, first off, I don't know why decltype isn't working. I get the error C2327: 'Foo<T>::container' : is not a type name, static, or enumerator, suggesting something, but I'm just not going to try figuring it out.

    Secondly...
    Quote Originally Posted by StainedBlue View Post
    I want to take advantage of how iterators are really pointers underneath it all. If i sort the list, the iterators go with the elements they point to. And so if the wrapper objects contain the original container values, plus an added iterator pointer, i should be able to achieve O(1) efficiency of getting an iterator into any of the projected containers, at the desired location. That's the idea anyway.
    ...I am uncertain of this. I don't know if sort invalidates the iterators, but I do believe it should. A iterator is a pointer to a certain element, not just a glorified pointer. So I'd say you're invoking undefined behavior.
    But just for giggles, I'll C++0x-ify your code:
    Code:
    #include <iostream>
    #include <algorithm>
    #include <list>
    
    int main()
    {
        std::list<int> base;
        std::list<decltype(base.begin())> base_iterators;
    	typedef decltype(*base.begin()) base_t;
    
        for( int i = 0; i < 10; i++)
            base.push_back(i);
    
        for(auto it = base.begin(); it != base.end(); it++)
            base_iterators.push_back(it);
    
        std::list<int>::iterator it_ptr = base.begin();
        std::cout << "Beginning: " << *it_ptr << "\n\n";
    
    	std::for_each(base.begin(), base.end(), [](base_t i) { std::cout << i << "\n"; });
    
        base.sort([](base_t a, base_t b) { return a > b; });
    
        std::cout << "\nEnd: " << *it_ptr << "\n\n";
    	std::for_each(base.begin(), base.end(),  [](base_t i) { std::cout << i << "\n"; });
    
        std::cout << "\nIterating backwards from the end:\n\n";
        std::list<int>::iterator it_copy = it_ptr;
        for (int i = 0; i < 3; i++, it_copy--)
            std::cout << *it_copy << "\n";
    
        return 0;
    }
    Also, is this going to work? I don't know.
    You made a fatal flaw when creating the code. You were binding a pointer to a temporary. That's illegal. Your compiler should have picked up that.
    Basically, it was the line
    Code:
        std::list<int>::iterator* it_ptr = &base.begin();
    begin() returns a temporary and you're creating a pointer to it. You're lucky it works or worked.
    You need to create an iterator to begin first, then you can create a pointer to it.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  6. #6
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    I don't know if sort invalidates the iterators, but I do believe it should. A iterator is a pointer to a certain element, not just a glorified pointer.
    std::sort() doesn't invalidate iterators. It swaps values pointed at by iterators, so the values of dereferenced iterators may change.
    list::sort() doesn't invalidate iterators either. However, the standard doesn't specify where iterators point afterwards. Note, however, that the SGI STL documents that iterators still point to the same elements, i.e. dereferencing them yields the same value as before. The position of the iterators in the sequence may be different though, so iterators that previously formed a range might not do so after the sort. This behavior is what I would expect from most list implementations, simply because list sorting is probably done by relinking. However, for cheap objects (e.g. fundamental types), the implementation might instead do actual value swapping, because that could be cheaper than relinking nodes in the doubly-linked list - after all, moving a node in a list consists of six pointer assignments. Swapping two nodes consists of eight assignments, whereas swapping two values is just three assignments.
    So I wouldn't rely on iterators after a list::sort().
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  7. #7
    ...and never returned. StainedBlue's Avatar
    Join Date
    Aug 2009
    Posts
    168
    So I wouldn't rely on iterators after a list::sort().
    That's a ........er.

    So my next idea would be to come up with my own sequential access scheme.

    Basically running down the container and assigning next/prev in my wrapper objects, simple.

    My only concern would be dangling pointers, because I have no intention of fully recreating the functionality of the linked list, although, direct access to the STL node's next/prev would've solved this! -obvious joke.
    goto( comeFrom() );

  8. #8
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Well, first off, I don't know why decltype isn't working.
    decltype itself works (assuming c++0x mode). But it declares the type to be a reference (because that's the result of dereferencing the iterator), and an error occurs later when it ends up trying to declare something like:

    Code:
    Bar (   SomeT& const &, iterator* index = 0 )
    I suppose one could try work around with

    Code:
    typedef typename std::remove_reference<decltype(*container.begin())>::type T_type;
    but now I can't see how on earth the use of Container::value_type could be deprecated...
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  9. #9
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    No, there is something else...
    If the decltype is inside the struct, I get illegal indirection for some reason.
    If I move it outside the struct (but inside the class Foo), I simply get C2327: 'Foo<T>::container' : is not a type name, static, or enumerator.
    There is something more amiss than just a reference, if there is a reference, that is.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #10
    The larch
    Join Date
    May 2006
    Posts
    3,573
    I think there are changes to rules concerning nested classes and perhaps VC++ has not yet implemented it.

    In the old standard draft (9.7):

    Code:
              class enclose {
              public:
                  int x;
                  static int s;
                  class inner {
                      void f(int i)
                      {
                          int a = sizeof(x); // error: refers to enclose::x
                          x = i;   // error: assign to enclose::x
                          s = i;   // ok: assign to enclose::s
                      }
                  };
              };
    In N3000:

    Code:
    struct enclose {
        int x;
        static int s;
        struct inner {
            void f(int i) {
                int a = sizeof(x); // OK: operand of sizeof is an unevaluated operand
                x = i; // error: assign to enclose::x
                s = i; // OK: assign to enclose::s
            }
        };
    };
    decltype doesn't evaluate the operand either. Examples shortened.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Polynomials and ADT's
    By Emeighty in forum C++ Programming
    Replies: 20
    Last Post: 08-19-2008, 08:32 AM
  2. Undefined Reference Compiling Error
    By AlakaAlaki in forum C++ Programming
    Replies: 1
    Last Post: 06-27-2008, 11:45 AM
  3. Drawing Program
    By Max_Payne in forum C++ Programming
    Replies: 21
    Last Post: 12-21-2007, 05:34 PM
  4. Certain functions
    By Lurker in forum C++ Programming
    Replies: 3
    Last Post: 12-26-2003, 01:26 AM
  5. Half-life SDK, where are the constants?
    By bennyandthejets in forum Game Programming
    Replies: 29
    Last Post: 08-25-2003, 11:58 AM