2012-01-10 3 views
3
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(); (который является функцией-членом). И:Вывод аргумента шаблона аргумента C++. Зачем?

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

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

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

Iter.h: 272: 27: Примечание: кандидат шаблон игнорируется: не удалось аргумент шаблона дедукции [3]

Почему?

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

+0

какой тип 'Итератор :: Ref'? – sth

+0

[Связанный?] (Http://stackoverflow.com/questions/6677072/overload-resolution-failure-when-streaming-object-via-implicit-conversion-to-str) –

+2

'bool CWorm :: getLocal(); 'не может соответствовать' boost :: function ', потому что он не принимает аргумент. –

ответ

0

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

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

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

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); 
2

Вы имеете в виду 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, в междунар. Кого выбрать? C++ запрещает выводить типы шаблонов из таких параметров, как тот, который вы объявили.


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

1

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

У IBM есть list of supported template parameter deductions.

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

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

В преобразовании не участвует. Он просто должен соответствовать 'Ref >' с 'Ref >'. Я всегда думал, что это не будет проблемой (и я также не понимаю, почему это так, я вполне уверен, что видел подобные вещи в другом месте). Кроме того, это уже определяет 'T', поэтому материал' boost :: function' больше не имеет значения. – Albert

+0

А, ты это прогнал? "' worms() 'возвращает' Ref Ref> '. – Albert

+0

А, прости, пропустил этот момент. Тогда проблема заключается в преобразовании в boost :: function - вам понадобится оболочка makeFn или какая-то альтернатива ей. –

Смежные вопросы