【问题标题】:How are templated static member functions parsed?如何解析模板化的静态成员函数?
【发布时间】:2012-10-02 14:59:58
【问题描述】:

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

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&lt;T&gt;s 更改为 Base&lt;int&gt;,它将编译。如果您将对Bar() 的调用更改为Base&lt;T&gt;::template Bar&lt;false&gt;(5);,它也会编译。

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

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

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

【问题讨论】:

  • 我认为我的常见问题解答并没有解释为什么在实例化时不只解析模板(如果我理解正确,这就是这里所问的)。我的常见问题解答认为编译器在定义模板时会尽早解析模板。所以我不知道欺骗链接是否真的没问题。
  • 刚读完,虽然不是我要找的唯一东西,但仍然是非常好的信息!

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


【解决方案1】:
void Foo() { Base<T>::Bar<false>(5); } 

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

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

否则Base&lt;T&gt;::Bar 将被解析为非模板成员,&lt; 将被解析为小于

至于为什么需要template,原因是两阶段查找。该错误在第一次传递期间触发,在类型被替换之前,因此编译器不知道Base&lt;T&gt; 的定义是什么。例如,考虑您为具有非模板 Bar 成员(例如 int 成员)的 int 添加了一个专门化的 Bar。在将T 替换为Foo 之前,编译器不知道该类型是否存在特化。

【讨论】:

  • 此错误在第二遍中给出。您可以通过显式特化来定义基类,以使他的确切行编译。如果您定义了合适的运算符
  • @JohannesSchaub-litb:我有点迷路了......代码中的operator&lt;(有意)在哪里使用?编译器抱怨在代码Base&lt;T&gt;::Bar&lt;false 中没有合适的Base&lt;T&gt;::Barfalse,但用户很可能不想将成员模板与布尔值进行比较,而是调用@ 的特化987654340@,参数为 5。
  • 我确实对这样做的原因感兴趣,而不仅仅是让代码编译不正确。不过,我认为它必须是第二阶段,因为我可以对 Base 进行专门化,声明一个静态整数 Bar,可以将其与 false 进行比较(我刚刚编写了一个快速测试来验证)
  • 当然编译器不知道是否有意使用了operator
  • @Rollie:在第一阶段验证模板,解析非依赖名称并固定依赖名称的类型(即Bar被确定为非类型,非模板)。正是在这个阶段出现了问题,因为Bar 被确定为非模板并且解析确定&lt;小于 比较。第一阶段完成后,&lt; 的含义固定为比较,在第二阶段编译器遇到operator&lt;(Base&lt;int&gt;::Bar,false) [...]
猜你喜欢
  • 2010-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多