Есть ли способ иметь одну статическую переменную для шаблона класса (для всех типов) без нарушения инкапсуляции - PullRequest
3 голосов
/ 11 февраля 2010

Мне нужен способ иметь одну статическую переменную для всех типов типов моего шаблона

template <class T> class Foo { static Bar foobar;};

Хорошо, строка выше будет генерировать объект Bar с именем foobar для каждого типа T, но это не то, что я хочу, я в основном хочу способ объявления переменной типа Bar, поэтому каждый объект типа Foo имеет доступ к той же переменной foobar, независимо от T.

Я пытался использовать другой класс для хранения личных вещей, но это не работает, потому что стандарт не разрешает такие вещи, как template <class T> friend class Foo<T>;

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

Bar Foo_DO_NOT_TOUCH_THIS_PLEASE_foobar;
template <class T> class Foo { static Bar& foobar;};
template <class T> Bar& Foo<T>::foobar=Foo_DO_NOT_TOUCH_THIS_PLEASE_foobar;

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

Кроме того, это решение будет довольно запутанным, когда вам придется объявлять множество статических методов аналогичным образом, поскольку вам, скорее всего, придется экстенсивно использовать ключевое слово friend, например friend RetType Foo_detail::StaticFunc(ArgT1, ArgT2).

И у пользователей не будет приятного интерфейса, поскольку они не могут использовать эти функции, как они используются для Foo<T>::someFunc(), но вместо этого им придется вызывать что-то вроде Foo_static::someFunc() (если вы используете пространство имен Foo_static для открытых статических функций ).

Так есть ли какое-либо другое решение, которое не нарушает инкапсуляцию и / или не вводит много синтаксических издержек?

EDIT: основываясь на всех ваших ответчиках, я попробовал следующее, и оно работает как задумано:

typedef int Bar;
template <class T> class Foo;

class FooBase
{
    static Bar foobar;
    public:
        template <class T> friend class Foo;
};
Bar FooBase::foobar;

template <class T> class Foo : public FooBase
{
    public:
    using FooBase::foobar;
};

Преимущество этого решения в том, что пользователи не могут наследовать от FooBase.

Ответы [ 4 ]

9 голосов
/ 11 февраля 2010

Возможно наследовать статический член?

class OneBarForAll
{
protected:
  static Bar foobar;
};

template <class T>
class Foo : public OneBarForAll
{

};

Будет сделано много Foo<T>, но только один OneBarForAll.

Одна потенциальная проблема с этим заключается в том, что ничто не мешает другим пользователям кода наследовать от OneBarForAll и все равно изменять foobar.

В идеале вам нужен шаблонный друг, поскольку он наилучшим образом описывает требования к доступу вашего дизайна, но C ++ в настоящее время не позволяет этого.

4 голосов
/ 11 февраля 2010

Синтаксис для

template <class T> friend class Foo<T>;

есть

template <class T> friend class Foo;

(что означает, что каждый экземпляр Foo является другом класса, в котором вы его определяете)

Так что, возможно, вы можете использовать решение, которое вы исключили ранее.

3 голосов
/ 11 февраля 2010

вы могли бы сделать:

struct Base {
  static Foo foo;
};
//init foo here

template<typename T>
struct Derived : Base {
...
};
...
Derived<Bar>::foo;

Работает на г ++

1 голос
/ 11 февраля 2010

Почему бы не наследовать от не шаблонного базового класса?

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