C ++ автоопределение аргументов шаблона? - PullRequest
17 голосов
/ 15 июня 2011

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

template <typename T1, typename T2>
class Farm
{
  private:
    T1 *task1;
    T2 *task2;
  public:
    // save them so that I can use them when invoking call operator
    Farm(T1 *_t1, T2 *_t2): task1(_t1), task2(_t2) { }

    void operator()()
    {
      // invoke call operator, meaning a farm could be a task (arbitrary nesting)
      (*task1)();
      (*task2)();
    }
};
int main()
{
    ... create two pointer(A *a, B *b...)
    Farm(a,b); // error: missing template arguments before ‘(’ token

    Farm<A, B>(a,b); // in this works, it works
}

Проблема заключается в автоматическом обнаружении аргументов шаблона, которое в этом случае не работает.Что я делаю не так и как я могу добиться этого шаблона параметров неявного обнаружения компилятором gcc.

Спасибо!

Ответы [ 3 ]

16 голосов
/ 15 июня 2011

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

Это делается следующим образом и называется шаблоном Object Generator .(спасибо @Itjax!)

template <typename T1, typename T2>
Farm<T1, T2> makeFarm(T1* a, T2* b) {
      return Farm<T1,T2>(a,b);
}

// silly example
Farm<T1,T2> farm = makeFarm(a,b);

// better example
template<typename T>
void plow(T& farm) { farm.applyTractor(...); }

void blah() {
    plow(makeFarm(b,a)) 
}

Этот шаблон довольно часто появляется при использовании lambda / bind / foreach и подобных частей, когда вы хотите создать временный объект шаблонного класса с некоторыми аргументами и избежать указанияих тип, обычно отправляющий его в другую шаблонную функцию (std::for_each) или полиморфный объект (std::function).

Примечание: Функция генератора обычно встроена и с оптимизацией копирования-тамвероятно, в вашем коде вообще не будет вызываться конструктор копирования.Если вы не можете скопировать свой объект, makeFarm () должна вместо этого возвращать умный указатель (std::unique_ptr предпочтительнее в современном C ++).

4 голосов
/ 15 июня 2011

Обычный обходной путь - предоставить шаблонную функцию, которая возвращает реальную реализацию.Стандартная библиотека C ++ использует это много, например, с std :: make_pair.

Пример:

template<typename T>
struct foo_t {
    ...
};

template<typename T>
foo_t<T> foo(T const &f) {
    return foo_t<T>(f);
}

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

1 голос
/ 15 июня 2011

Вы можете добавить базовый класс для класса Farm:

class FarmBase
{
  public:
    virtual ~FarmBase(){}

    virtual void operator()() = 0;
};


template <typename T1, typename T2>
class Farm : public FramBase
{
  private:
    T1 *task1;
    T2 *task2;
  public:
    // save them so that I can use them when invoking call operator
    Farm(T1 *_t1, T2 *_t2): task1(_t1), task2(_t2) { }
    virtual ~Farm(){}

    virtual void operator()()
    {
      // invoke call operator, meaning a farm could be a task (arbitrary nesting)
      (*task1)();
      (*task2)();
    }
};
template< typename A, typename B >
FarmBase* Create( A *a, B *b )
{
  return new Farm< A, B >( a, b );
}

, тогда основной выглядит так:

int main()
{
    //... create two pointer(A *a, B *b...)

    FarmBase *fobj = CreateFarm( a, b );
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...