Помогите сохранить intrusive_ptr шаблонного класса в std :: map - PullRequest
4 голосов
/ 12 апреля 2009

У меня есть небольшой класс шаблона типа Locker, содержащийся в boost :: intrusive_ptr, который я хочу сохранить внутри std :: map:

template <typename T>
bool LockerManager<T>::
  AddData(const std::string& id, T* pData)
{

  boost::intrusive_ptr<Locker<T> > lPtr(Locker<T>(pData)); // Line 359 - compiles

  mMap.insert(make_pair(id, lPtr));  // Line 361 - gives error
}

Locker - это просто контейнерный класс; его конструктор выглядит так:

template <typename T>
Locker<T>::
  Locker(T* pData)
  : IntrusivePtrCountable(),
    mpData(pData),
    mThreadId(0),
    mDataRefCount(0)
{} 

В своем тесте этого класса я пытаюсь сделать следующее:

class Clayton
{
public:
  static int count;

  Clayton()
  { mNumber = count++;}

  void GetNumber()
  { cerr<<"My number is: "<<mNumber<<endl; }

private:
  int mNumber;
};

int Clayton::count = 0;

class ClaytonManager
{
public:
  bool AddData(const std::string& id, Clayton* pData)
  { return mManager.AddData(id, pData); }

private:
  LockerManager<Clayton> mManager;
};

Я получаю следующую ошибку компиляции:

Compiling LockerManagerTest.cpp                             : /usr/local/lib/gcc/i686-pc-linux-gnu/3.4.6/../../../../include/c++/3.4.6/bits/stl_pair.h: In constructor `std::pair<_T1, _T2>::pair(const std::pair<_U1, _U2>&) [with _U1 = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _U2 = boost::intrusive_ptr<Locker<Clayton> > (*)(Locker<Clayton>), _T1 = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _T2 = boost::intrusive_ptr<Locker<Clayton> >]':
../Utilities/include/LockerManager.h:361:   instantiated from `bool LockerManager<T>::AddData(const std::string&, T*) [with T = Clayton]'
src/LockerManagerTest.cpp:35:   instantiated from here
/usr/local/lib/gcc/i686-pc-linux-gnu/3.4.6/../../../../include/c++/3.4.6/bits/stl_pair.h:90: error: no matching function for call to `boost::intrusive_ptr<Locker<Clayton> >::intrusive_ptr(boost::intrusive_ptr<Locker<Clayton> > (* const&)(Locker<Clayton>))'
/usr/local/boost-1.36.0/include/boost-1_36/boost/intrusive_ptr.hpp:94: note: candidates are: boost::intrusive_ptr<T>::intrusive_ptr(const boost::intrusive_ptr<T>&) [with T = Locker<Clayton>]
/usr/local/boost-1.36.0/include/boost-1_36/boost/intrusive_ptr.hpp:70: note:                 boost::intrusive_ptr<T>::intrusive_ptr(T*, bool) [with T = Locker<Clayton>]
/usr/local/boost-1.36.0/include/boost-1_36/boost/intrusive_ptr.hpp:66: note:                 boost::intrusive_ptr<T>::intrusive_ptr() [with T = Locker<Clayton>]
Command exited with non-zero status 1
0:05.40

Пожалуйста, помогите

Ответы [ 2 ]

2 голосов
/ 13 апреля 2009

На самом деле, intrusive_ptr уже имеет оператор <и определен конструктор копирования, так что это не проблема. </p>

Было две главные вещи, которые нам не хватало. Во-первых, нам нужно было использовать value_type вместо make_pair, чтобы избежать неявного преобразования типов в операторе insert. Во-вторых, мы упустили тот факт, что конструктор intrusive_ptr принимает указатель на тип, вокруг которого он создается.

Итак, последний, рабочий метод выглядит так:

// ---------------------------------------------------------------------------
// LockerManager::AddData
// ---------------------------------------------------------------------------
template <typename T>
bool LockerManager<T>::
  AddData(const std::string& id, T* pData)
{
  Lock<MutualExclusion> lLock(mMutex);

  if ((pData == NULL) || (mMap.find(id) != mMap.end()))
    return false;

  mMap.insert(typename std::map<std::string, boost::intrusive_ptr<Locker<T> > >::value_type(id, new Locker<T>(pData)));

  return true;
} // LockerManager::AddData
1 голос
/ 12 апреля 2009

Компилятор делает все возможное, чтобы помочь здесь. Вам необходимо определить метод со следующей сигнатурой:

boost::intrusive_ptr<Locker<Clayton> >::intrusive_ptr(
    boost::intrusive_ptr<Locker<Clayton> > (* const&)(Locker<Clayton>)
):

Вам нужно определить конструктор копирования для типов, которые вы храните в std :: map, вот что пытается передать это сообщение об ошибке. Вам также следует реализовать оператор <, чтобы верно следующее: </p>

- ( x < x ) == false
- if ( x < y ), then !( y < x )
- if ( x == y ), then ( x < y ) == ( y < x ) == false
- if ( x < y ) and ( y < z ), then ( x < z )

Для многих встроенных типов C ++ обеспечит их для вас, поэтому некоторые люди не знают, что вам нужно делать для хранения пользовательских объектов в std :: map и других контейнерах STL.

...