Переменные как параметры для шаблонов в C ++ - PullRequest
1 голос
/ 01 ноября 2009

Я пытаюсь начать изучать C ++, и у меня проблема.

Я пытаюсь создать шаблон функции,

template<multimap<string, double> arr>
void calculate(string key) {
}

и используйте его так:

multimap<string, double> arr;
vector<string> keys;
// ...
for_each(keys.begin(), keys.end(), calculate<arr>);

Но я не компилирую:

Illegal type for non-type parameter
и т. Д.

Пожалуйста, помогите мне. Как архивировать поведение, которое я ожидаю? Я действительно не хочу создавать обратный вызов для каждого for_each и т. Д. (Может быть, замыкания сделали меня более ленивым, чем это требовалось для C ++, и я должен, но я не хочу верить)

(кстати, есть ли способ получить вектор с ключами из мультикарты?)


Я пробовал

typedef multimap<string, double> my_map;

template<my_map arr>

до сих пор не работает

Ответы [ 4 ]

4 голосов
/ 01 ноября 2009

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

Итак, давайте сделаем вашу функцию такой:

void calculate(const string &key, multimap<string, double>& myMap) 
{
    // do something...
}

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

multimap<string, double> map1;
vector<string> v = getValuesForMyVector();
for_each(v.begin(), v.end(), bind2nd(ptr_fun(calculate), map1);

Итак, ptr_fun(calculate) преобразует calculate, который является указателем на функцию, в специальный класс, называемый pointer_to_binary_function<string, multimap<string, double>, void>, для которого определена operator() для вызова вашей функции, то есть требуется 2 параметры.

bind2nd(ptr_fun(calculate), map1) возвращает binder2nd<string, void>, для которого все еще определено operator(), но теперь он принимает только 1 параметр. Второй параметр привязан к map1. Это позволяет for_each работать с этим функциональным объектом.

Конечно, вы застряли, используя эти 2 адаптера, если выполняете функцию. Лучше сделать класс:

class MapCalculator
{
public:
    MapCalculator(multimap<string, double>& destination) : map_(destination) {}
    void operator()(const string& s)
    {
        // do something...
    }
private:
    multimap<string, double>& map_;    
};

// later...

multimap<string, double> map1;
vector<string> v = getValuesForMyVector();
for_each(v.begin(), v.end(), MapCalculator(map1));
2 голосов
/ 01 ноября 2009

Неверно утверждать, что параметр шаблона может быть только типом или целым числом. Это может быть больше, включая ссылку или указатель. Но вы не можете иметь значение map в качестве параметра значения. Итак, , хотя предпочтительным способом написания кода является написание функтора с operator(), вы все равно можете передать карту в качестве аргумента шаблона.

template<multimap<string, double> &arr>
void calculate(string key) {
}

multimap<string, double> arr;

int main() {
  vector<string> keys;
  for_each(keys.begin(), keys.end(), &calculate<arr>);
}

Вы должны знать о последствиях:

  • Можно передавать только нелокальные переменные и только нестатические переменные - нельзя использовать переменные с внутренней связью.
  • Это очень странно и запутает большинство программистов на C ++.

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

0 голосов
/ 01 ноября 2009

Многие динамические языки (и несколько необычных скомпилированных языков, таких как c ++ 0x!) Имеют нечто, называемое замыканиями, которые похожи на функции, но также являются объектами первого класса в том смысле, что они заключают в себе некоторое локальное состояние, в котором они находятся. используемый.

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

struct calculate {
    multimap<string, double> arr;
    void operator()(string key) {
    }
};

Использование его очень похоже.

multimap<string, double> arr;
vector<string> keys;

calculate Calc;
Calc.arr = arr;
// ...
for_each(keys.begin(), keys.end(), Calc);
0 голосов
/ 01 ноября 2009

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

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