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)
,它就不会抱怨。我想知道为什么它不能像这样推断出模板参数。我可以以某种方式使它不同,以便它能够自动推断出类型吗?
答案 0 :(得分: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的参数,即int。它应该选哪一个? C ++不允许从您声明的参数中推导出模板类型。
通过更新您的问题,您的意思是::Ref<Iterator<T> >
。我认为那应该是可以推断的,因为typedef Iterator<CWorm*>::Ref
是::Ref<Iterator<CWorm*> >
,它似乎应该能够推导出T
。我不确定为什么它不起作用。
答案 1 :(得分: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 ++中更具可读性,即使它可能不那么通用,也几乎不会使代码变得更糟。
答案 2 :(得分: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);