2

I apologise for the verbosity of this example, I contrived it out of a project. The commented, Item 1 and item two, are important in the following code.

#include <boost/intrusive/set.hpp>

struct x : public boost::intrusive::set_base_hook<>
{
    int y;
};

struct finder
{
    bool operator()(const int & i, const x & _x) const
    { return i < _x.y;}
    bool operator()(const x & _x, const int & i) const
        { return _x.y < i;}
};

class trampoline
{
public:
    void bounce() const /* item 1 */
    {
        /*item 2*/
        boost::intrusive::set<x>::iterator it = _set.find(1,finder()); 
    }

    boost::intrusive::set<x> _set;
};

int main()
{
    trampoline t;
    t.bounce();
}

I cannot take a non-const itereator to my member container (item 2) where the function in scope is const, if I switch the iterator to a const_iterator everything works fine, or if I make the enclosing function non-const it works as well. Makes perfect sense, now, after an hour of reverse engineering the problem from the following error message:

test.cc: In member function ‘void trampoline::bounce() const’:test.cc:21: error: conversion from ‘boost::intrusive::tree_iterator<boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<x, boost::intrusive::rbtree_node_traits<void*, false>, (boost::intrusive::link_mode_type)1u, boost::intrusive::default_tag, 3>, std::less<x>, long unsigned int, true> >, true>’ to non-scalar type ‘boost::intrusive::tree_iterator<boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<x, boost::intrusive::rbtree_node_traits<void*, false>, (boost::intrusive::link_mode_type)1u, boost::intrusive::default_tag, 3>, std::less<x>, long unsigned int, true> >, false>’ requested

Which eventually led me to the following template definition (/include/boost/intrusive/detail/tree_node.hpp +72):

/////////////////////////////////////////////////////////////////////////////
//                                                                         //
//                   Implementation of the tree iterator                   //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

// tree_iterator provides some basic functions for a 
// node oriented bidirectional iterator:
template<class Container, bool IsConst>

Sufficed it so say I solved the problem shortly after....

How the hell does that template get passed IsConst from the callsite of the enclosing function ? My brain is ready to explode (for all I know its something simple, but I am mystified). A detailed explanation with a step by step implementation to explain the mechanics would be helpful.

I have a similar question here similar with regards to the type-deduction/aliasing of the template mechanism of C++. references are appreciated, but they need to be mulled over into knowledge :D. If you have the patience to answer this question, you might want to try to form a discourse on the other question.

Community
  • 1
  • 1
Hassan Syed
  • 20,075
  • 11
  • 87
  • 171

2 Answers2

1

like that?

Foo<false> bar();
Foo<true> bar() const;
Anycorn
  • 50,217
  • 42
  • 167
  • 261
1

Wouldn't the find() member function of boost::intrusive::set simply have a const and non-const overload? I mean, that's how I would do it:

template <typename T /*...*/ >
class set {
  //... 
  public:
    template <bool isConst>
    class iterator {
      //....
    };
    iterator<true> find(/*..*/) const; //notice the const
    iterator<false> find(/*..*/);      //notice no const
};

This really isn't meta-programming magic, just good old fashion const-correctness.

Mikael Persson
  • 18,174
  • 6
  • 36
  • 52
  • Come on, it can't be that simple, no wonder my brain was ready to explode. I'm old school, everything is a `void *` type of person =D. So the const overload is picked up from the member objects by the compiler =D and then their is the artificial const semantics enforcement by violating type aliasing (--i.e., their isn't a valid copy constructor available). I was getting confused by the "their is no return type polymorhism in C++" mantra running in my head. – Hassan Syed Mar 16 '11 at 19:24
  • If you think of the object instance on which the function is called as the first (hidden) parameter of the function call, then it makes prefect sense in the overloading mechanism. The cv-qualifiers of the member function should be thought of as the cv-qualification of this first (hidden) parameter. The compiler finds the best matching overload, so a non-const object calls a non-const function if it is available since it is a better matching overloaded version. – Mikael Persson Mar 16 '11 at 20:20