С ++ не удалось вывести аргументы шаблона.Зачем? - PullRequest
3 голосов
/ 10 января 2012
template<typename T>
Ref<Iterator<T> > GetFilterIterator(Ref<Iterator<T> > i, boost::function<bool(T)> pred) {
    return new FilterIterator<T>(i, pred);
}


Ref<Iterator<CWorm*> > x = GetFilterIterator(worms(), &CWorm::getLocal);

И worms() возвращает Ref<Iterator<CWorm*> Ref>, и есть bool CWorm::getLocal(); (который является функцией-членом).И:

template<typename T> struct Ref {
     // ...
};

template<typename T> struct Iterator {
     // ...
};

Это не приведет к выводу аргумента шаблона:

Iter.h: 272: 27: примечание: шаблон кандидата игнорируется: сбой вывода аргумента шаблона [3]

Почему?

Если я вызову его с указанным аргументом шаблона, то есть GetFilterIterator<CWorm*>(worms(), &CWorm::getLocal), он не будет жаловаться.Интересно, почему он не может вывести аргумент шаблона, как этот.И могу ли я как-то изменить его, чтобы он мог автоматически определять тип?

Ответы [ 3 ]

2 голосов
/ 11 января 2012

Вы подразумеваете typname Iterator<T>::Ref для типа первого параметра в объявлении шаблона GetFilterIterator? Если это так, это не выводимый контекст для параметров типа шаблона.

Рассмотрим:

template<>
struct Iterator<Foo> {
    typedef int Ref;
};
template<>
struct Iterator<Bar> {
    typedef int Ref;
};

GetFilterIterator(int(0),f);

И Iterator<Foo>::Ref, и Iterator<Bar>::Ref соответствуют параметру, переданному в GetFilterIterator, int. Какой из них выбрать? C ++ запрещает вывод типов шаблонов из параметров, подобных объявленным вами.


С обновлением вашего вопроса похоже, что вы имеете в виду ::Ref<Iterator<T> >. Я думаю, что это должно быть выводимым тогда, и так как typedef Iterator<CWorm*>::Ref равен ::Ref<Iterator<CWorm*> >, кажется, что он должен быть способен вывести T Я не уверен, почему это не работает.

1 голос
/ 11 января 2012

Компилятор не может вывести аргументы шаблона, потому что подгонка к параметрам будет означать нетривиальное преобразование - сначала в Iterator<T>, а затем в Ref<Iterator<T> >, которые оба требуют пользовательских преобразований. Кроме того, прямое преобразование указателя на функцию-член в boost :: function аналогично нетривиально для компилятора.

IBM имеет список поддерживаемых вычетов параметров шаблона .

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

template <typename T>
Ref<Iterator<T> > makeIteratorRef(T val)  {
    return Ref<Iterator<T> >(Iterator<T>(val));
}

template <typename T>
boost::function<bool (T)> makeFn(bool (T::*fn) () const)  {
    boost::function<bool (T)> res = boost::bind(fn, _1);    
    return res;
}

...

Ref<Iterator<CWorm*> > x = GetFilterIterator(makeIteratorRef(worms()), makeFn(&CWorm::getLocal));

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

Кстати, я думаю, вы слишком усложняете простые вещи:

for (auto it = worms().begin(); it != worms().end(); ++it)
  if (it->isLocal()) { 
    // Do something
  }

Этот код более читабелен в C ++, и хотя он может быть не таким общим, он вряд ли ухудшит код.

0 голосов
/ 13 января 2012

Благодаря подсказке от Xeo к здесь о том, что неявные преобразования типов не допускаются при выводе аргументов шаблона, я подумал, а может ли второй параметр вызвать проблемы здесь.Я думал, что он будет делать вывод типа слева направо, и как только тип будет выведен, это больше не проблема (для указателя функции на boost::function cast).

Кажется, я ошибался иэто была именно проблема.

Другая версия того же самого решения позволяет избежать проблемы:

template<typename T>
struct PartialFuncWrapper {
    ::Ref<Iterator<T> > i;
    PartialFuncWrapper(::Ref<Iterator<T> > _i) : i(_i) {}
    typename Iterator<T>::Ref operator()(boost::function<bool(T)> pred) {
        return new FilterIterator<T>(i, pred);      
    }
};

template<typename T>
PartialFuncWrapper<T> GetFilterIterator(::Ref<Iterator<T> > i) {
    return PartialFuncWrapper<T>(i);
}

Тогда я могу написать:

Ref<Iterator<CWorm*> > x = GetFilterIterator(worms())(&CWorm::getLocal);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...