Дилемма параметров шаблона - PullRequest
3 голосов
/ 17 января 2010

У меня дилемма. Предположим, у меня есть шаблон класса:

template <typename ValueT>
class Array
{
public:
    typedef ValueT ValueType;
    ValueType& GetValue()
    {
        ...
    }
};

Теперь я хочу определить функцию, которая получает ссылку на класс и вызывает функцию GetValue (). Я обычно рассматриваю следующие два способа:

Метод 1:

template <typename ValueType>
void DoGetValue(Array<ValueType>& arr)
{
    ValueType value = arr.GetValue();
    ...
}

Метод 2:

template <typename ArrayType>
void DoGetValue(ArrayType& arr)
{
    typename ArrayType::ValueType value = arr.GetValue();
    ...
}

Почти нет разницы между этими двумя методами. Даже вызов обеих функций будет выглядеть одинаково:

int main()
{
    Array<int> arr;
    DoGetValue(arr);
}

Теперь, какой из двух является лучшим? Я могу вспомнить некоторые минусы и плюсы:

Преимущества 1 метода:

Параметр является реальным классом, а не шаблоном, поэтому пользователю проще понять интерфейс - очень очевидно, что параметр должен быть массивом. В методе 2 вы можете догадаться только по названию. Мы используем ValueType в функции, поэтому он более понятен, чем когда он скрыт внутри Array и должен быть доступен с помощью оператора scope.

Кроме того, ключевое слово typename может сбивать с толку многих опытных программистов, не разбирающихся в шаблонах.

Способ 2 плюсы:

Эта функция более "верна" своей цели. Когда я думаю, если это так, мне не нужен класс Array. Что мне действительно нужно, так это класс, который имеет метод GetValue и тип ValueType. Это все. То есть этот метод является более общим.

Этот метод также меньше зависит от изменений в классе Array. Что если параметры шаблона Array изменены? Почему это должно влиять на DoGetValue? На самом деле все равно, как определяется массив.

Каждый раз, когда у меня такая ситуация, я не уверен, что выбрать. Какой у тебя выбор?

Ответы [ 3 ]

4 голосов
/ 17 января 2010

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

1 голос
/ 17 января 2010

Если ваша функция очень специфична для ArrayType, и ни один другой шаблон не удовлетворит его требованиям к интерфейсу, используйте # 1, так как он короче и конкретнее: случайный читатель информируется, что он работает на ArrayType.

Если есть вероятность, что другие шаблоны будут совместимы с DoGetValue, используйте # 2, так как он более общий.

Но одержимость бесполезна, поскольку между ними достаточно легко переходить.

0 голосов
/ 17 января 2010

Мой друг предложил еще два, несколько более экстремальных метода:

Метод 3: дает вам возможность использовать типы, которые не имеют :: ValueType.

template <typename ArrayType, typename ValueType = ArrayType::ValueType>
void DoGetValue(ArrayType& arr)
{
    ValueType value = arr.GetValue();
    ...
}

Метод 4: классный способ заставить массив быть классом с одним параметром шаблона.

template <template <typename> class ArrayType, typename ValueType>
void DoGetValue(ArrayType<ValueType>& arr)
{
    ValueType value = arr.GetValue();
    ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...