可能的编译器错误?使用从模板化静态成员函数检索的指针调用模板化方法时,无法进行自动推理

Possible compiler bug? auto deduction isn't possible when calling a templated method with a pointer retrieved from a templated static member function

本文关键字:方法 调用 自动推理 指针 静态成员 错误 编译器 函数 检索      更新时间:2023-10-16

UPDATE 2

为什么这被标记为重复项? Where and why do I have to put the “template” and “typename” keywords?没有回答这个问题。此处描述的行为在任何地方都没有提及(您不会在那里找到有关auto的预期行为的单个注释(。

这不是重复的,特别是因为不同的编译器中存在冲突的行为。


更新

就像GCC一样,clang也无法编译:

17 : error: expected expression
return p->is<true>();
^

但是,在 MSVC 上,具有auto检测的代码已成功编译

显然,某处存在编译器错误。


现场示例

请考虑以下类:

struct A {
    template<bool>
    bool is() const {
        return true;
    }
    template<bool>
    static A* get() {
        static A a;
        return &a;
    }
};

如果模板函数,例如

template<bool cond>
bool foo() {
    auto p = A::get<cond>();
    return p->is<true>();
}

尝试调用A::is<bool>,失败惨败:

main.cpp: In function 'bool foo()':
main.cpp:17:24: error: expected primary-expression before ')' token
     return p->is<true>();
                        ^
main.cpp: In instantiation of 'bool foo() [with bool cond = true]':
main.cpp:21:22:   required from here
main.cpp:17:17: error: invalid operands of types '<unresolved overloaded function type>' and 'bool' to binary 'operator<'
     return p->is<true>();
                 ^

但是,如果只有我们将auto替换为显式类型(A*(:

template<bool cond>
bool foo() {
    A* p = A::get<cond>();
    return p->is<true>();
}

它有效。

这是什么原因呢?

你需要

return p->template is<true>();

因为编译器最初并不知道is是一个模板。


一些更深刻的解释。跟

A* p = A::get<cond>();
return p->is<true>();

编译器即使在分析代码时也知道pA* 类型,因此它看到p->is是一个模板。

auto p = A::get<cond>();
return p->is<true>();

编译器最初不知道p的类型。它只有在实例化A::get<cond>之后才会知道这一点,而这只有在实例化foo时才会发生。所以它不知道p->is是一个模板。(它可能很容易不是一个模板,因为你有专门的A版本,比如说,true模板参数。

延伸阅读:我必须在哪里以及为什么必须放置"模板"和"类型名称"关键字?


引用标准 [14.2.4]:

当成员模板专用化的名称出现在 之后时。 或 ->在后缀表达式中或限定 id 中的嵌套名称说明符之后,并且后缀表达式的对象表达式为 类型相关或限定 id 中的嵌套名称说明符引用 到依赖类型,但名称不是当前 实例化 (14.6.2.1(,成员模板名称必须以 关键字模板。否则,该名称被假定为命名 非模板。

我认为这清楚地解释了观察到的是正确的行为。如果没有autop的类型就不依赖于类型。有了auto,就变得与类型相关。