在 gcc 8.2 而非 MSVC 19 中编译的模板代码

Template code that compiles in gcc 8.2 but not MSVC 19

这个示例脚本在 gcc 8.2 中编译得很干净,但在 Visual Studio 2019 中它 returns error C3200: 'bar<int>': invalid template argument for template parameter 'bar', expected a class template 在 'new' 出现的行:

template<typename T, template<typename> class bar>
class foo;

template<typename T>
class bar
{
    friend class foo<T, bar>;
};

template<typename T, template<typename> class bar>
class foo
{
};

class baz : bar<int>
{
public:
    void mash()
    {
        auto whoosh = new foo<int, bar>();
    }
};

int main(int argc, char **argv)
{
    baz A;
    A.mash();

    return 0;
}

仔细阅读,我认为问题可能是该行中的第二个模板参数现在是定义明确的类型而不是模板,但即使那是真的我不知道该怎么办。将“bar”替换为“decltype(bar)”对我没有任何帮助。

我欢迎任何建议。

https://godbolt.org/z/rrGdvf763

我承认,我不知道谁对谁错(见下文)。混淆似乎是因为 class 模板 baz 继承自 bar<int>,标识符 bar 被解释为 bar<int>。奇怪的是 bar 本身使用 bar 来引用模板而不是 bar<T>。编译器不同意。无论如何,如果您将代码更改为:

,您包含在一致性视图中的所有编译器都会接受代码
class baz : bar<int>
{
public:
    void mash()
    {
        auto whoosh = new foo<int, ::bar>();
    }
};

Live Demo

正如 Jarod42 指出的那样:

From injected-class-name#In_class_template: "In the following cases, the injected-class-name is treated as a template-name of the class template itself: - it is used as a template argument that corresponds to a template template parameter". so msvc's bug.

而且,感谢 aschepler link,标准中的官方措辞可以在第 1 段的 [temp.local] 中找到。

所以我上面所说的“奇怪”是意料之中的。例如:

 template <typename T>
 struct moo {
      moo some_method();
      //^ refers to moo<T>
      foo<int,moo> some_other_method();
      //      ^ refers to moo
 };

而您遇到的是 msvc 没有正确实现该异常的情况。