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
error: too few template arguments for class template 'A'
unless I remove the forward declaration; g++ accepts both.
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).
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).
template<class T> using myname = some::templatething<T>;
Then you can use myname
In your case stick a template<class T,class S=X> using A = n2::A<T,S>;
in your 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.
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"
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. 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.
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
So you need to get that default in there right away!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With