Фридинг шаблона параметра - PullRequest
7 голосов
/ 03 февраля 2011

Невозможно подружить параметр шаблона, потому что стандарт запрещает его.Как я мог бы эффективно получить то же самое тогда?

То, что я хочу, это в основном тип, который нельзя использовать вне объекта, которому он принадлежит.Почему это не относится к делу, но если вы действительно должны знать, я пытаюсь сформулировать набор умных указателей, которые решают проблему совместного использования собственного ресурса.Таким образом, я собираюсь сделать что-то вроде этого, если это сработало:

template < typename T, typename Owner >
struct accessible_member
{
private:
  accessible_member() : val(T()) {}
  accessible_member(T const& t) : val(t) {}

  operator T& () { return val; }
  operator T const& () const { return val; }

  member_ptr<T> operator & () { return member_ptr<T>(val); }

  friend class Owner;
};

Таким образом, класс не может содержать этот объект как член, если он не объявит себя владельцем, и если он достаточно глупыйчтобы разоблачить его как есть, использовать его за пределами класса будет так глупо.

Ответы [ 6 ]

5 голосов
/ 03 февраля 2011

Вы правы насчет C ++ 98/03. Однако C ++ 0x (n3225 11.4 / 3) позволяет вам делать это с помощью следующего синтаксиса:

friend Owner;

Посмотрите, позволит ли ваш компилятор сделать это. Попробуйте включить поддержку C ++ 0x. В противном случае обходные пути более уродливы:

struct Owner
{
    typedef Owner self;
};

...

Тогда, в зависимости от вашего компилятора, один из:

friend typename Owner::self;

или

friend class Owner::self;
3 голосов
/ 03 февраля 2011

Вы можете использовать это, а затем позволить всем владельцам наследовать от Владелец .

Затем вы можете использовать класс Владелец , чтобы конфиденциально обернуть методы, используемые в available_member .
available_member теперь доступно для Владелец . Friend не наследуется, поэтому вы можете предоставить (обернуть) необходимые методы, чтобы все классы, наследующие Owner, могли использовать available_member .

Это двухуровневое решение, но оно поддерживает уровень инкапсуляции.

template < typename U >
struct Owner 
{
   protected:
   accessible_member<U> newAccessible_member() { return accessible_member<U>(); }
   accessible_member<U> newAccessible_member(U const& u) { return accessible_member<U>(u); }
   .....

};

template < typename T >
struct accessible_member
{
private:
  accessible_member() : val(T()) {}
  accessible_member(T const& t) : val(t) {}

  operator T& () { return val; }
  operator T const& () const { return val; }

  member_ptr<T> operator & () { return member_ptr<T>(val); }


  template < typename U> friend class Owner;
};

Затем вы можете косвенно использовать available_member в структурах, которые наследуются от Owner с использованием защищенных методов:

struct Blah: Owner<int>
{
   void Dosomething() {
       accessible_member<int> blah= newAccessible_member();
   }
};

Посмотрите на последний пример на Шаблон друзей .

1 голос
/ 04 февраля 2011

7.1.5.3 p2 говорит:

[Примечание: это подразумевает, что в шаблоне класса с параметром типа шаблона T объявлен класс друга T;неправильно сформирован.]

В результате любое решение, которое позволяет вам его любым способом, будет нестандартным.

0 голосов
/ 25 декабря 2011

Насколько я понимаю, это будет работать с небольшими изменениями под C ++ 98. Он собран без каких-либо предупреждений для меня с g++-4.1 -Wall -Wextra -pedantic -ansi -std=c++98

Просто изменить

friend Owner;

до

struct Wrapper { typedef Owner type; };
friend class Wrapper :: type;

(я получил ответ на Stackoverflow, этот вопрос возникал несколько раз: Параметр шаблона в качестве друга )

0 голосов
/ 04 февраля 2011

Единственный обходной путь, который я вижу, довольно уродлив и использует CRTP:

template <typename T>
struct CanUseAccessibleMember
{
    template <typename T>
    static const T& get(const accessible_member<T>& m)
    { return static_cast<const T&>(m); }

    // Etc. You can even specialize this class.
};

struct ExampleOwner 
    : protected CanUseAccessibleMember<ExampleOwner>
{
    // Do whatever you want with accessible members here
    // but you have to use the get syntax
};

template <typename T, typename Owner>
class accessible_member
{
    // Implement members as you did

    friend struct CanUseAccessibleMember<Owner>;
};
0 голосов
/ 03 февраля 2011

Как насчет простого определения частного вложенного типа, который тривиально наследуется от available_member? Что-то вроде

class Owner
{
    template < typename T >
    class accessible_member : public ::accessible_member< T > {};
};

Конечно, это по-прежнему означает, что оригинальный тип accessible_member доступен любому, поэтому, возможно, он не слишком полезен, если подумать.

...