嵌套命名空间中模板类的前向声明:默认模板参数应该放在哪里?

iav*_*avr 5 c++ templates namespaces forward-declaration

我在嵌套命名空间中有一个模板类的前向声明

namespace n1
{
    namespace n2
    {
        template <typename T, typename S>
        struct A;
    }
    using n2::A;
}
Run Code Online (Sandbox Code Playgroud)

后跟一个定义,实际上是在一个不同的文件中,其间有东西:

struct X { };

namespace n1
{
    namespace n2
    {
        template <typename T, typename S = X>
        struct A { };
    }
    using n2::A;
}
Run Code Online (Sandbox Code Playgroud)

然后以下总是好的:

n1::n2::A <int> a;
Run Code Online (Sandbox Code Playgroud)

但这个捷径

n1::A <int> a;
Run Code Online (Sandbox Code Playgroud)

在clang中给出编译错误

error: too few template arguments for class template 'A'
Run Code Online (Sandbox Code Playgroud)

除非我删除了前瞻性声明; g ++接受两者.

clang似乎与第一个不包含默认模板参数的声明一致(我不能包含它,因为我还没有定义X).

如果我使用单个命名空间没有问题(但这不是一个解决方案).

我做错了什么,或者哪个编译器是正确的?快捷方式如何与前向声明和嵌套命名空间一起工作?我需要他们所有人.

XS的前向声明+默认参数当然有效,但实际上太繁琐(实际上有几十个,整个文件结构都会改变).

iav*_*avr 1

我发现这是一个最方便的解决方法:

namespace n1
{
    namespace n2
    {
        template <typename T, typename S>
        struct A;
    }

    namespace fwd { using n2::A; }
}

// stuff on n1::fwd::A;

struct X { };

namespace n1
{
    namespace n2
    {
        template <typename T, typename S = X>
        struct A { };
    }

    using n2::A;
}
Run Code Online (Sandbox Code Playgroud)

也就是说,将第一个 using 声明移动到另一个名称空间。现在“东西”可以是这样的:

namespace n1
{
    namespace stuff
    {
        using namespace fwd;

        template <typename T>
        struct R /*...*/;

        template <typename T, typename S>
        struct R <A <T, S> > /*...*/;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用A没有任何名称空间。我的项目中只有一个n1,但有很多n2,因此将所有 using 声明移到单个命名空间中n1::fwd会更方便,因为我不能只使用n1.