Пожалуйста, подпишитесь на официальный канал Codeforces в Telegram по ссылке https://t.me/codeforces_official. ×

Блог пользователя Scorpy

Автор Scorpy, 13 лет назад, По-русски

В проекте есть такие три файла:
http://pastebin.com/DFTqFqGc  (segtree.h)
http://pastebin.com/vYu1AYCa   (segtree.cpp)
http://pastebin.com/qAq8ALHi   (main.cpp)

Компилятор выводит ошибки:
c:\documents and settings\admin\мои документы\visual studio 2010\projects\segmenttree\segmenttree\seqtree.cpp(49): error C2953: 'SegmentTree' : class template has already been defined
          c:\documents and settings\admin\мои документы\visual studio 2010\projects\segmenttree\segmenttree\segtree.h(6) : see declaration of 'SegmentTree'

'max' is not a valid template type argument for parameter 'Func'

Какое слово ставить перед Func в определении шаблона и почему возникает первая ошибка?
Я же вроде бы не определяю, а только объявляю класс?

  • Проголосовать: нравится
  • +1
  • Проголосовать: не нравится

13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
  1. А в каких файлах/строках?
  2. Функции нельзя передавать как параметры - это указатели. Точнее, можно, но там будет немножко запутанного кода (говорим, что второй параметр template - это что-то в стиле (T*)(T, T) max - переменная). В STL'е используются функторы
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Да вот в том и дело, что скажем STL`евский sort спокойно принимает функции.
    • 13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      sort - это функция, а свой компаратор Вы передаёте как аргумент функции. Поэтому можно.
      Я сейчас еще покопался в template'ах, передать функцию как параметр шаблона не получилось. Обычные типы - пожалуйста, а вот сложную функцию - нет.
13 лет назад, # |
Rev. 2   Проголосовать: нравится +35 Проголосовать: не нравится

Первое. Нельзя разделять шаблон класса на два файла. Точнее, можно, но это называется extern template и никем не поддерживается. Чтобы много не писать, скажу:
  • убей segtree.h
  • убери #include "segtree.h" в segtree.cpp
  • переименуй segtree.cpp в segtree.h
  • допиши в новом segtree.h необходимые для его функционирования #include <vector> и #include <algorithm>
  • разберись с неизвестной переменной t в методе SegTree::get
Второе. Две функции по одному имени ты не передашь никуда и никогда. В твоем случае напрашивается такой вот класс:

struct maximum
{
    int operator () (int const &a)
    {
        return a;
    }
    int operator () (int const &a, int const &b)
    {
        return std::max(a, b);
    }
};


Далее, заменить SegmentTree<int, max> на <int, maximum>.

При этом все продолжает ругаться. Объясняю, почему. В определении SegmentTree<Item, Func> Func должно быть типом, а не значением (это поэтому тебе ругались на твой max), а ты к нему обращаешься как к классу. То есть, Func(a, b) - это не вызов функции, а вызов конструктора класса. Поэтому надо в определении SegmentTree добавить следующую строку:

Func func;

и все "вызовы" Func(a, b) надо заменить на func(a, b) - что действительно будет вызовом функции.
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Спасибо, огромное!!! Всё скомпилилось! Жаль нельзя поставить +100500
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Как передать обычный нормальный max, показываю на примере:


template <typename Value, typename Comparator>
    struct example
{
    Comparator comp;

    example(Comparator const &c) : comp(c) {}

    Value decideThree(Value const &a, Value const &b, Value const &c) const
    {
        return comp(comp(a, b), c);
    }
};

int max(int a, int b)
{
    return a > b ? a : b;
}

int main()
{
    example<int, int (*) (int, int)> example1(max);

    int max3 = example1.decideThree(1, 4, 3);
}
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Кстати, какой смысл так использовать шаблон? 
    • 13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      Именно так приходится делать, когда надо использовать в std::set или std::map свой компаратор.

      В std::sort и иже с ними тип компаратора выводится, поэтому не надо указывать всякие int (*) (int, int).
      • 13 лет назад, # ^ |
        Rev. 9   Проголосовать: нравится 0 Проголосовать: не нравится
        • 13 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится
          codeforces опять ест мои комментарии
          А разве нельзя в конструкторе написать что-то вроде Value (*) (Value, Value) comp?
          • 13 лет назад, # ^ |
              Проголосовать: нравится 0 Проголосовать: не нравится
            А с функтором что прикажешь делать? Не все же передают именно функции и именно с такой сигнатурой. Поэтому так.

            Ниже написал, как писать функции с автовыводом такой хрени.
    • 13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      Раз возникли вопросы, покажу, как можно описать функцию типа std::sort, при использовании которой необязательно указывать типы всего и вся:

      #include <iostream>

      template<typename V, typename C>
          V decideThree(V const &v1, V const &v2,
                        V const &v3, C const &c) {
          return c(v1, c(v2, v3));
      }

      int max(int a, int b) {
          return a > b ? a : b;
      }

      int main() {
          std::cout << decideThree(3, 1, 8, max) << std::endl;
          return 0;
      }