【问题标题】:C++ - Why is the 'template' keyword required here?C++ - 为什么这里需要“模板”关键字?
【发布时间】:2020-05-20 14:05:00
【问题描述】:

我有以下代码:

template <typename TC>
class C
{
    struct S
    {
        template <typename TS>
        void fun() const
        {}
    };

    void f(const S& s)
    {
        s.fun<int>();
    }
};

// Dummy main function
int main()
{
    return 0;
}

当同时使用 gcc 9.2 和 clang (9.0) 构建它时,由于调用 fun 需要 template 关键字,我遇到了编译错误。 Clang 显示:

error: use 'template' keyword to treat 'fun' as a dependent template name
        s.fun<int>();
          ^
          template 

我不明白为什么编译器认为funf 上下文中的从属名称,因为f 本身不是模板。如果我将C 更改为常规类而不是模板,则错误消失;但是,我不明白为什么首先应该出现错误,因为 Sf 都不依赖于 TC

奇怪的是,MSVC 19.22 编译得很好。


注意

在投票结束作为 Where and why do I have to put the "template" and "typename" keywords? 的骗子之前,请考虑这是一种特殊情况,即使 S 确实是一个从属名称,在 f 的上下文中,如果不是因为以下事实,它也不会是依赖的它们是当前实例化的成员。

【问题讨论】:

标签: c++ templates language-lawyer dependent-name


【解决方案1】:

Consider:

template<typename T>
struct C
{
    struct S
    {
        int a = 99;
    };

    void f(S s, int i)
    {
        s.a<0>(i);
    }
};

template<>
struct C<long>::S
{
    template<int>
    void a(int)
    {}
};

int main()
{
    C<int>{}.f({}, 0); // #1
    C<long>{}.f({}, 0); // #2
}

s.a&lt;0&gt;(i) 被解析为包含两个比较操作&lt;&gt; 的表达式,这对#1 很好,但对#2 失败。

如果这是changeds.template a&lt;0&gt;(i),那么#2 正常,而#1 失败。因此,template 关键字在这里绝不是多余的。

MSVC 是 capable 在同一程序中以两种方式解释表达式 s.a&lt;0&gt;(i)。但是根据标准这是不正确的;每个表达式应该只有一个解析供编译器处理。

【讨论】:

  • 我还没有完全理解这一点。您的示例表明,在这种情况下,您要么使用 C 的特化,要么使用另一个,但您永远不能同时实例化两者。 template 这里的关键字仍然不需要恕我直言,因为选择哪个S 取决于您实例化哪个C。如果没有 template 关键字,您将能够实例化两者,并且 f 的行为会因每个实例而异。
  • @Martin 的重点是每个标记在源文件中应该只有一个语法角色。例如,令牌&lt; 在一个模板实例中作为比较运算符而在另一个实例中作为左尖括号是不合适的。这是为了确保编译器可以将模板解析为 AST(带有模板类型的占位符)。
  • 这是有道理的。谢谢!
【解决方案2】:

fun 可能是也可能不是模板函数(或者可能根本不存在)取决于class C 的模板参数。

那是因为你可以专门化S(无需专门化C):

template <> struct C<int>::S {};

因为编译器在第一次查看class C时想知道fun是否是模板(在替换模板参数之前),所以template是必需的。

【讨论】:

  • 接下来,S 的这些新定义是否可以被f 访问。如果他们不能,那么有这个限制没有意义,因为f 无论如何都看不到他们。
  • @Martin GCC, Clang 和 MSVC f 确实找到了。
  • @bolov 是的,你可以专攻lots of different things
猜你喜欢
  • 1970-01-01
  • 2021-09-06
  • 1970-01-01
  • 2016-05-06
  • 1970-01-01
  • 2012-06-03
  • 1970-01-01
  • 2021-08-27
  • 2014-03-14
相关资源
最近更新 更多