Самоссылочный шаблон в шаблоне Аргумент - PullRequest
7 голосов
/ 10 декабря 2011

Что я могу сделать, чтобы сделать эту работу:

template<class C, class V, Test V::*>
class Test {
};

это дает мне ошибку компилятора:

unknown type name 'Test'

Это самоссылочный шаблон на данный момент, который не кажетсявозможный.Что можно сделать, чтобы заставить его работать?

РЕДАКТИРОВАТЬ:

Вот для чего мне это нужно.Я хочу реализовать двунаправленную (думаю, родитель-дочернюю) схему отношений с наименьшим минимумом усилий по написанию кода.

template <class O, class T, Reference<T, O, Reference O::*> T::* opposite>
class Reference
{
    T **data;
    int count;
public:
    Reference(): data(new T*[N]), count(0) {}
    ~Reference() {delete[] data;}
    Reference &add(T *t) {
        handleOtherSide();
        return link(t);
    }
    // a lot of stuff to implement this
};

Это класс коллекции.Вот как это будет использоваться:

class Partner
{
public:
    Reference<Partner, Address, &Address::partner> addresses;
};

class Address
{
public:
    Reference<Address, Partner, &Partner::addresses> partner;
};

Моя цель - предоставить все необходимое для работы Reference в качестве аргумента шаблона, чтобы не было необходимости предоставлять конструкторы для таких классов, как Partner и Address (в настоящее времяЯ предоставляю противоположный указатель на член в качестве конструктора arg, но для этого требуется наличие явных конструкторов для классов участников).Мне также нужно было бы передать или вычислить указатель «владельца» на класс Reference.Я оставил эту проблему здесь, потому что я хочу сосредоточиться на аспекте шаблона самоссылки.

Самый простой способ думать об этом - boost :: bimap.Но проблема с bimap заключается в том, что я не хочу вмещающий bimap, а только его левую и правую части.bimap также неосуществим, потому что это приведет к тому, что один bimap будет управлять всеми ассоциациями определенных отношений.Возможно, он будет содержать большое количество объектов, замедляющих операции на нем.

Ответы [ 2 ]

2 голосов
/ 10 декабря 2011

Вы ищете что-то подобное?Это не самоссылающийся шаблон, но вы можете указать производный класс как тип шаблона для базового класса, а базовый класс может вызывать производные методы и т. Д.:

template< typename PType, typename PDerived >
class TBase
{
  //do stuff with TDerived
 public:
  bool foo( void )
  {
   return ( static_cast< PDerived* > ( this )->bar() );
  }
};

template< typename PType >
class TDerived : public TBase< PType, TDerived< PType > >
{
  friend class TBase< PType, TDerived< PType > > ;
  //do stuff
 protected:
  bool bar( void )
  {
   return ( true );
  }
};

РЕДАКТИРОВАТЬ: еще раз, я не уверенваша конечная цель.Вот решение того, что вы хотите, или, по крайней мере, некоторый намек на то, что вы могли бы использовать для реализации своего дизайна.Единственное требование, которое я поставил, это то, что и TAddress, и TPartner имеют функцию с одинаковым именем.Смотрите, если это то, что вам нужно.В принципе, вы можете создать вспомогательный класс и использовать CRTP для доступа к функции-члену через указатель, но я не думаю, что вам это действительно нужно.

template< typename PType1, typename PType2 >
class TReference
{
 public:
  int mFlag;

  TReference() :
   mFlag( 0 )
  {
  }
  TReference( int fFlag ) :
   mFlag( fFlag )
  {
   std::cout << "Creating reference " << PType1::sName << " -> " << PType2::sName << "." << std::endl;
  }
  TReference< PType2, PType1 > AccessOpposite( void )
  {
   PType2 lTmp;
   lTmp.Opposite();

   return TReference< PType2, PType1 > ( -1 );
  }
};

class TPartner;

class TAddress
{
 public:
  static const char* sName;
  TReference< TAddress, TPartner > mRef;

  void Opposite( void )
  {
   std::cout << sName << "::Opposite" << std::endl;
  }
};

class TPartner
{
 public:
  static const char* sName;
  TReference< TPartner, TAddress > mRef;

  TReference< TAddress, TPartner > Opposite( void )
  {
   std::cout << sName << "::Opposite" << std::endl;
  }
};

const char* TAddress::sName = "TAddress";
const char* TPartner::sName = "TPartner";

int main( void )
{
 TAddress lAddress;
 TPartner lPartner;

 std::cout << lAddress.mRef.mFlag << " " << lPartner.mRef.mFlag << std::endl;

 lPartner.mRef = lAddress.mRef.AccessOpposite();

 std::cout << lAddress.mRef.mFlag << " " << lPartner.mRef.mFlag << std::endl;

 return ( 0 );
}
1 голос
/ 31 декабря 2011

Проблема в том, что я хочу добиться невозможного в C ++, по крайней мере, с помощью шаблонов и количества кода и классов, к которым я стремлюсь (читай: одна строка кода на члена). Он начинается с того, что компилятору нужны предварительные объявления и полностью определенные типы, что делает невозможным использование значений-членов и аргументов шаблона (в случае циклических зависимостей). Тогда невозможно иметь указатель члена в качестве аргумента шаблона, когда класс этого члена еще не полностью определен. Основная причина всего этого заключается в том, как работает компилятор: это однопроходный процесс. И я ничего не могу с этим поделать.

Решение состоит в том, чтобы использовать члены-ссылки или базовый класс стиля OO или контейнер boost :: any style, чтобы избежать шаблонов. С последними 2 может быть возможно иметь членов по значению.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...