5

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

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<'

如果将Base<T>Derived 中的 2 更改为Base<int>,它会编译。如果将调用更改Bar()Base<T>::template Bar<false>(5);,它也会编译。

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

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

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

4

1 回答 1

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>。例如,考虑您添加了具有非模板成员(例如成员)的Barfor的特化。在代入之前,编译器不知道该类型是否有专门化。intBarintTFoo

于 2012-10-11T21:00:15.673 回答