如何解析模板化的静态成员函数?

时间:2012-10-11 20:39:35

标签: c++ templates static c++11

我从来没有对模板参数推导如何真正起作用做出很好的解释,所以我不确定如何解释我在下面看到的行为:

template<typename T>
struct Base
{
protected:
    template<bool aBool = true>
    static void Bar(int)
    {
    }
};

template<typename T>
class Derived : public Base<T>
{
public: 
    void Foo() { Base<T>::Bar<false>(5); } 
};

int main()
{
    Derived<int> v;
    v.Foo();
    return 0;
}

此代码不会构建,并提供错误:

main.cpp: In instantiation of 'void Derived<T>::Foo() [with T = int]':
main.cpp:25:8:   required from here main.cpp:19:15: error: invalid
operands of types '<unresolved overloaded function type>' and 'bool'
to binary 'operator<'

如果您将Derived中的2 Base<T>更改为Base<int>,则会进行编译。如果您将对Bar()的呼叫更改为Base<T>::template Bar<false>(5);,它也会进行编译。

我看到的一个解释是,编译器不知道Bar是一个模板,可能是因为在声明Derived的特化之前它不知道Base是什么。但是,一旦编译器开始为Foo()生成代码,Base<T>已经定义,并且Bar的类型可以确定。是什么导致编译器假设符号Bar而不是模板,并尝试应用operator<()

我认为它与在编译过程中评估模板的规则有关 - 我想我正在寻找的是对这个过程的一个很好的全面解释,这样下次我遇到像这样的代码下面,我可以在没有堆栈溢出的好人的帮助下推断出答案。

注意我正在使用g ++ 4.7进行编译,支持c ++ x11。

1 个答案:

答案 0 :(得分:3)

void Foo() { Base<T>::Bar<false>(5); } 

在此上下文中,Base<T>是一个从属名称。要访问从属名称的成员模板,您需要添加template关键字:

void Foo() { Base<T>::template Bar<false>(5); } 

否则Base<T>::Bar将被解析为非模板成员,而<将被解析为少于

至于为什么template是必需的,原因是两阶段查找。在第一次传递期间触发错误,在替换类型之前触发,因此编译器不知道 Base<T>的定义是什么。例如,您考虑为Bar添加了int的特殊化,其中包含非模板Bar成员(例如int成员)。在将T替换为Foo之前,编译器不知道该类型是否存在特化。