在类模板中推导模板成员函数

时间:2018-02-05 17:35:46

标签: c++ templates

为什么在以下示例中无法从T的签名中推断出fn

template<int I>
struct Class {
    template<typename T>
    Class &operator <<( void (*)(const Class<I> &, const T &) ) { return *this; }
};

struct Ot { };

template<int I>
void fn(const Class<I> &, const Ot &) { }

int main() {
    Class<1>() << fn;
}

相反,以下不将operator<<作为常规成员的示例是合法的:

template<int I>
struct Class {
    Class &operator <<( void (*)(const Class<I> &) ) { return *this; }
};

struct Ot { };

template<int I>
void fn(const Class<I> &) { }

int main() {
    Class<1>() << fn;
}

2 个答案:

答案 0 :(得分:2)

因为就像您使用Class<1>而不是Class一样,您还必须将模板参数提供给功能模板fn

Class<1>() << fn<1>;

此外,您可能希望从operator <<

返回引用
template<typename T>
Class & operator <<( void (*)(const Class<I> &, const T &) ) { return *this; }
      ^

答案 1 :(得分:0)

归结为功能模板的模板参数可以是显式指定的,也可以从传递给函数的参数中推导出来。

在您的示例中,编译器无法确定fn的模板参数,因为在Class<1>::operator<<()的调用中没有传递参数。因此,您必须明确指定它:fn<1>(或任何您想要的)。完成此操作后,fn的类型是明确的,编译器可以从T的第二个参数类型(即fn&lt; 1&gt;)中推断出Class<1>::operator()的类型。

换句话说,fn的类型并不清楚。你可以通过fn&lt; 2&gt;到Class&lt; 1&gt; :: operator&lt;&lt;()。请考虑以下代码:

Class<1> << fn<2>;   // fn<2> is not fn<1>
Class<1> << fn<1>;   // OK too, of course
Class<1> << fn;      // error! fn<?>