已知依赖上下文规则,非依赖上下文为何需使用"template"关键字?
template关键字? 嘿,这个问题其实挺典型的,尤其是在用Boost.DI这类依赖注入库的时候——哪怕你已经摸透了依赖上下文里template的必要性,碰到这种看似“非依赖”的场景还是会懵一下。咱们一步步拆解清楚:
首先得纠正一个常见误区:不是只有当前上下文是模板函数/类时才需要template关键字。关键在于编译器在解析代码时,能不能提前确定你要调用的成员是一个模板方法。
举个极简的例子,模拟Boost.DI里的bind和to逻辑:
// 模拟Boost.DI的Binder模板类 template <typename T> struct Binder { // to是一个模板方法 template <typename U> Binder<T>& to() { return *this; } }; // 模拟Boost.DI的bind模板函数 template <typename T> Binder<T> bind() { return Binder<T>{}; } int main() { // 错误写法:编译器会把<当成小于号解析 // bind<int>().to<double>(); // 正确写法:必须加template告诉编译器to是模板方法 bind<int>().template to<double>(); }
你看,main是个普通函数,完全没有模板参数,但调用bind<int>().to<double>()时还是会报错。原因很简单:
编译器在解析这行代码时,还没来得及实例化bind<int>这个模板函数,所以它不知道bind<int>()返回的Binder<int>类型里的to是个模板方法——它会误以为你在写bind<int>().to < double > (),也就是把to当成一个成员变量,然后做小于号比较,这显然完全不符合你的意图。
回到你的Boost.DI代码场景:di::bind<events::Manager>()是一个模板函数调用,返回的是Boost.DI内部定义的某个模板类实例(比如di::detail::binding<events::Manager>之类的),而这个类的to方法本身又是一个模板方法。编译器在解析di::bind<events::Manager>().to<events::Manag...>时,同样无法提前知道to是模板方法,所以必须用template关键字明确标记:“这个to是模板方法,后面的<>是它的模板参数列表,不是比较运算符!”
总结一下:只要你调用的是模板函数返回的模板类实例的模板方法,哪怕当前上下文不是模板,编译器都需要template关键字来消除歧义,避免把模板参数的<>当成比较符号。
内容的提问来源于stack exchange,提问作者Jakub

