简体   繁体   English

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

[英]Forward declaration of template class in nested namespace: where should default template arguments go?

I have a forward declaration of a template class in a nested namespace 我在嵌套命名空间中有一个模板类的前向声明

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

followed by a definition, which in fact is in a different file, with stuff in between: 后跟一个定义,实际上是在一个不同的文件中,其间有东西:

struct X { };

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

Then the following is always ok: 然后以下总是好的:

n1::n2::A <int> a;

but this shortcut 但这个捷径

n1::A <int> a;

gives a compile error in clang 在clang中给出编译错误

error: too few template arguments for class template 'A'

unless I remove the forward declaration; 除非我删除了前瞻性声明; g++ accepts both. g ++接受两者。

clang appears to stay with the first declaration which does not include the default template argument (and I cannot include it, because I have not defined X yet). clang似乎与第一个不包含默认模板参数的声明保持一致(我不能包含它,因为我还没有定义X )。

There is no problem if I use a single namespace (but this is not a solution). 如果我使用单个命名空间没有问题(但这不是一个解决方案)。

What am I doing wrong, or, which compiler is correct? 我做错了什么,或者哪个编译器是正确的? How can the shortcut work together with the forward declaration, and the nested namespace? 快捷方式如何与前向声明和嵌套命名空间一起工作? I need all of them. 我需要他们所有人。

Forward-declaring X + default argument for S of course works, but would be too tedious (there are dozens of them actually, and the whole file structure would change). S的前向声明X +默认参数当然有效,但是太繁琐了(实际上有几十个,整个文件结构都会改变)。

template<class T> using myname = some::templatething<T>;

Then you can use myname 然后你可以使用myname

In your case stick a template<class T,class S=X> using A = n2::A<T,S>; 在你的情况下template<class T,class S=X> using A = n2::A<T,S>;粘贴template<class T,class S=X> using A = n2::A<T,S>; in your n1 在你的n1

Just wrote a gem of an answer related to this Symbol not found when using template defined in a library there btw, have a read. 刚写了一个与这个符号相关的答案的宝石, 在使用库中定义的模板时找不到 btw,有一个读取。

Okay it's not been ticked, so I'm gonna help some more! 好吧,它没有被勾选,所以我会帮助更多!

will not compile 不会编译

#include <iostream>

namespace n1 {
namespace n2 {
template<class U,class V> struct A;
}
template<class U,class V> using A = n2::A<U,V>;
}

static n1::A<int,int>* test;

struct X {};
namespace n1 {
namespace n2 {
template<class U,class V> struct A {};
}
template<class U,class V=X> using A = n2::A<U,V>;
}

static n1::A<int> test2;


int main(int,char**) {

    return 0;
}

Why? 为什么? C++'s "first declaration rule" C ++的“第一声明规则”

Here's the compiler's output: 这是编译器的输出:

make all 
if ! g++ -Isrc -Wall -Wextra -O3 -std=c++11 -g -gdwarf-2 -Wno-write-strings  -MM src/main.cpp >> build/main.o.d ; then rm build/main.o.d ; exit 1 ; fi
g++ -Wall -Wextra -O3 -std=c++11 -g -gdwarf-2 -Wno-write-strings  -Isrc -c src/main.cpp -o build/main.o
src/main.cpp:26:17: error: wrong number of template arguments (1, should be 2)
 static n1::A<int> test2;
                 ^
src/main.cpp:13:47: error: provided for ‘template<class U, class V> using A = n1::n2::A<U, V>’
 template<class U,class V> using A = n2::A<U,V>;
                                               ^
src/main.cpp:26:24: error: invalid type in declaration before ‘;’ token
 static n1::A<int> test2;
                        ^
src/main.cpp:16:24: warning: ‘test’ defined but not used [-Wunused-variable]
 static n1::A<int,int>* test;
                        ^
src/main.cpp:26:19: warning: ‘test2’ defined but not used [-Wunused-variable]
 static n1::A<int> test2;
                   ^
make: *** [build/main.o] Error 

Okay it's whining about unused variables, fair enough, but notice it's reference to line 13, that's because it's used the first definition default template arguments are really quite primitive and I can't quote specification at you right now. 好吧,它对未使用的变量抱怨,公平,但注意它是对第13行的引用,那是因为它使用了第一个定义默认模板参数非常原始,我现在不能引用规范。 https://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fdefault_args_for_templ_params.htm https://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fdefault_args_for_templ_params.htm

that may offer some insight though. 这可能会提供一些见解。

Anyway notice that: 无论如何注意到:

This compiles 这编译

#include <iostream>

namespace n1 {
namespace n2 {
template<class U,class V> struct A;
}
template<class U,class V> using A = n2::A<U,V>;
}

static n1::A<int,int>* test;

struct X {};
namespace n1 {
namespace n2 {
template<class U,class V> struct A {};
}
template<class U,class V=X> using B = n2::A<U,V>;
}

static n1::B<int> test2;


int main(int,char**) {

    return 0;
}

Because B has no prior definition. 因为B没有先前的定义。

Build output 构建输出

make all 
if ! g++ -Isrc -Wall -Wextra -O3 -std=c++11 -g -gdwarf-2 -Wno-write-strings  -MM src/main.cpp >> build/main.o.d ; then rm build/main.o.d ; exit 1 ; fi
g++ -Wall -Wextra -O3 -std=c++11 -g -gdwarf-2 -Wno-write-strings  -Isrc -c src/main.cpp -o build/main.o
src/main.cpp:16:24: warning: ‘test’ defined but not used [-Wunused-variable]
 static n1::A<int,int>* test;
                        ^
src/main.cpp:26:19: warning: ‘test2’ defined but not used [-Wunused-variable]
 static n1::B<int> test2;
                   ^
g++  build/main.o  -o a.out

See, fine :) 看,好:)

Remember with forward declarations you can only use *s and &s (as they are of known size, fixed size infact) - oh and &&s 记住使用前向声明你只能使用* s和&s(因为它们已知大小,固定大小) - 哦和&& s

So you need to get that default in there right away! 所以你需要立即在那里获得默认值!

I have found this as a most convenient workaround: 我发现这是一个最方便的解决方法:

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;
}

That is, move the first using-declaration to another namespace. 也就是说,将第一个using声明移动到另一个命名空间。 Now the 'stuff' could go like this: 现在'东西'可能是这样的:

namespace n1
{
    namespace stuff
    {
        using namespace fwd;

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

        template <typename T, typename S>
        struct R <A <T, S> > /*...*/;
    }
}

using A without any namespaces. 使用A而没有任何名称空间。 There is only one n1 in my project, but lots of n2 , so moving all forward using-declarations in a single namespace n1::fwd is more convenient, given that I cannot just use n1 . 我的项目中只有一个n1 ,但是很多n2 ,所以在单个命名空间n1::fwd使用声明向前移动更方便,因为我不能只使用n1

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM