Как можно избежать дублирования спецификации шаблона класса для каждой функции-члена? - PullRequest
6 голосов
/ 16 ноября 2010

Если у меня есть такая спецификация класса шаблона,

template <typename T>
class MyClass {
public:
    void fun1();
    // ...
    void funN();
};

template <typename T>
void MyClass<T>::fun1() {
    // definition
}

// ...

template <typename T>
void MyClass<T>::funN() {
    // definition
}

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

template <typename T, typename U>
class MyClass {
    // ...
};

Затем я должен изменить каждое определение функции (fun1, ..., funN), чтобы оно соответствовало спецификации шаблона класса:

template <typename T, typename U>
void MyClass<T,U>::fun1() { //... }

Существуют ли стратегии, позволяющие избежать этого? Могу ли я использовать макросы, например

#define DFLT_TEMPLATE template<typename T, typename U>
#define DFLT_CLASS  class<T,U>

DFLT_TEMPLATE
void DFLT_CLASS::fun1() { // ... }

Или это считается плохой практикой?

Ответы [ 7 ]

5 голосов
/ 16 ноября 2010

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

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

2 голосов
/ 16 ноября 2010

Сколько функций-членов у вас есть, что это проблема?

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

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

1 голос
/ 16 ноября 2010

Насколько это возможно, поместите определения функций в определение шаблона класса.Это шаблон, поэтому, если вы не используете компилятор Comeau, они не будут отключены в другом TU.

Если функции используют что-то, что определено между определением класса иопределение функции, тогда вы можете играть трюки, чтобы сделать эту вещь зависимой от параметра шаблона, даже если «на самом деле» это не так.Например:

template <typename T>
struct Foo {
    void usebar();
};

struct Bar {
    int a; 
    Foo<int> circularity; // circular dependency between Foo and Bar
    Bar() : a(3) {}
};

template <typename T> void Foo<T>::usebar() {
    Bar b;
    std::cout << b.a << "\n";
}

Становится:

// we only have to write "same" once
template <typename T, typename U>
struct same {
    typedef U type;
};

struct Bar;

template <typename T>
struct Foo {
    void usebar() {
        typename same<T,Bar>::type b;
        std::cout << b.a << "\n";
    }
};

struct Bar {
    int a; 
    Foo<int> circularity; // circularity gone
    Bar() : a(3) {} 
};

Или на самом деле в этом случае просто:

struct Bar;

template <typename T, typename B = Bar>
struct Foo {
    void usebar() {
        B b;
        std::cout << b.a << "\n";
    }
};

struct Bar {
    int a;
    Foo<int> circularity;
    Bar() : a(3) {}
};

Во всех случаях поддерживается следующий код:

int main() {
    Foo<int> f;
    f.usebar();
}
1 голос
/ 16 ноября 2010

Наследование лучше, чем макрос.

Если вы хотите изменить только несколько функций и переменных, заставьте специализированный класс наследовать общий класс, который предоставляет общие функции / переменные.

1 голос
/ 16 ноября 2010

да, вы можете, но не забывайте использовать "#undef DFLT_TEMPLATE" и "#undef DFLT_CLASS" в конце файла, чтобы избежать предупреждений компилятора, если в вашем проекте есть несколько шаблонов с одинаковыми определениями макросов

0 голосов
/ 16 ноября 2010

Возможно, есть некоторые (более или менее плохие) обходные пути, но вы определенно указываете на «отсутствующую» функцию C ++: class namespace extension.
Некоторые люди уже предлагали расширить C ++ таким образом:
http://www.lrde.epita.fr/dload//20080709-Seminar/ordy-classnamespaces.pdf

namespace foo
{
  class bar
  {
    typedef int baz_t;
    baz_t my_method ();
  };
}
namespace class foo::bar
{
  baz_t my_method ()
  {
  // ...
  }
}

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

Макросы плохие, потому что они позволяют вам писать функции редактирования кода там, где вы должны писать программы. Если вы хотите редактировать код, используйте ваш редактор (sed, M-x replace- *, Find & Replace ...)

0 голосов
/ 16 ноября 2010

Я бы посчитал этот подход плохой практикой.На что вы жалуетесь, что вы изменили изменили свой дизайн (вам нужен дополнительный параметр шаблона) и теперь хотите сэкономить при вводе текста kludge?

Введение макросов снизит читабельностьвашего кода.Определения препроцессора, безусловно, имеют свое место, но лично я никогда не отстаиваю их на том основании, что меня не беспокоит изменение моих функций.

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