Мета-магия шаблонов C ++, механизм удержания квалификации на сайте вызова шаблона

Прошу прощения за многословие этого примера, я придумал его из проекта. Прокомментированные пункты 1 и два важны в следующем коде.

#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();
}

Я не могу взять неконстантный итератор в свой контейнер-член (элемент 2), где функция в области видимости является константой, если я переключу итератор на константный итератор, все будет работать нормально, или если я сделаю включающую функцию неконстантной, она также будет работать . Теперь, после часа реверс-инжиниринга, имеет смысл понять проблему из следующего сообщения об ошибке:

test.cc: В функции-члене 'void trampoline :: bounce () const': test.cc: 21: error: преобразование из '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> 'в нескалярный тип' 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> 'запрошено

Что в конечном итоге привело меня к следующему определению шаблона (/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>

Этого хватило, так сказать, вскоре после этого я решил проблему ....

Как, черт возьми, этот шаблон передается IsConst с сайта вызова включающей функции? Мой мозг готов взорваться (насколько я знаю, это что-то простое, но я озадачен). Было бы полезно подробное объяснение с пошаговой реализацией механики.

У меня есть аналогичный вопрос здесь, похожий на Что касается вывода типов / псевдонимов механизма шаблонов C ++. ссылки приветствуются, но они должны быть переработаны в знания: D. Если у вас хватит терпения ответить на этот вопрос, вы можете попытаться обсудить другой вопрос.


person Hassan Syed    schedule 16.03.2011    source источник


Ответы (2)


Разве функция-член find () boost::intrusive::set не будет просто иметь перегрузку const и неконстантную? Я имею в виду, как бы я это сделал:

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

На самом деле это не магия метапрограммирования, а просто старая добрая константная корректность.

person Mikael Persson    schedule 16.03.2011
comment
Да ладно, это не может быть так просто, неудивительно, что мой мозг был готов взорваться. Я олдскульный, все void * тип человека = D. Таким образом, перегрузка const берется из объектов-членов компилятором = D, а затем используется искусственное принудительное применение семантики констант, нарушая псевдонимы типов (- т. Е. Их недопустимый конструктор копирования доступен). Меня смутила мантра C ++, которая звучит в моей голове - это полиморфизм невозвратного типа. - person Hassan Syed; 16.03.2011
comment
Если вы думаете об экземпляре объекта, для которого функция вызывается, как о первом (скрытом) параметре вызова функции, тогда это имеет смысл в механизме перегрузки. CV-квалификаторы функции-члена следует рассматривать как CV-квалификацию этого первого (скрытого) параметра. Компилятор находит наиболее подходящую перегрузку, поэтому неконстантный объект вызывает неконстантную функцию, если она доступна, поскольку это более подходящая перегруженная версия. - person Mikael Persson; 16.03.2011

как это?

Foo<false> bar();
Foo<true> bar() const;
person Anycorn    schedule 16.03.2011