Consider next example :
#include <iostream>
#include <typeinfo>
template< int N, typename T >
struct B
{
struct C;
};
template< typename T >
struct B< 0, T >::C
{
typedef T type;
};
template< int N, typename T >
struct B< N, T >::C
{
typedef T type[N];
};
int main()
{
std::cout<<"n=0 type = " << typeid( B< 0, float >::C::type ).name() << std::endl;
std::cout<<"n=5 type = " << typeid( B< 5, float >::C::type ).name() << std::endl;
}
When compiled using g++ (version 4.3.0)
g++ dfg.cpp -ansi -pedantic -Wall
the compile error is :
dfg.cpp:13: error: qualified name does not name a class before ‘{’ token
dfg.cpp: In instantiation of ‘B<0, float>::C’:
dfg.cpp:25: instantiated from here
dfg.cpp:20: error: ISO C++ forbids zero-size array
What I am really trying to archive is to have different Imp implementation depending on the enum value (in the example, instead of an enum, I used int, but it shouldn't matter).
Can someone explain why is this not allowed?
Why am I getting the first error?
(this one : qualified name does not name a class before ‘{’ token)
Regarding the pimpl implementation depending on a template parameter, I created a new question (with better example) here
You can't define C
outside B
this way - C
doesn't exist for the B
specialization you're creating. If you want to specialize B::C, you need to specialize B. Are you trying to do the following?
template< int N, typename T >
struct B
{
struct C {
typedef T type[N];
};
};
template< typename T >
struct B< 0, T >
{
struct C {
typedef T type;
};
};
Alternatively, you can do something like:
template< int N, typename T >
struct B
{
struct C;
};
template< typename T >
struct B< 0, T > {
struct C;
};
template< typename T >
struct B< 0, T >::C
{
typedef T type;
};
template< int N, typename T >
struct B< N, T >::C
{
typedef T type[N];
};
This partially specializes B for 0 and forward declares C, so that B<0, T>::C
can be defined.
This is not valid:
template< typename T >
struct B< 0, T >::C
{
typedef T type;
};
You can specialize members of class templates, but only for implicit instantiations of those class templates. This means in plain English: Only if you give values for all the template arguments of the enclosing class template (whose member you need to specialize).
template< >
struct B< 0, int >::C
{
typedef T type;
};
What you wrote is the definition of a B<0, T>::C
, which is a member of a class template partial specialization of B<N, T>
. Such a partial specialization does not exist, therefor, the compiler errored out.
You have several options to solve this. One is
template< int N, typename T >
struct B
{
template<typename N1, typename T1>
struct CMember { typedef T1 type[N1]; };
template<typename T1>
struct CMember<0, T1> { typedef T1 type; };
struct C {
typedef typename CMember<N, T>::type type;
};
};
Note that explicit specializations (non-partial) cannot be put into the class template directly (so, template<> struct CMember<0, int> { ... }
would be ill-formed when writting inside the body of B
). You would need to define the "selector" template outside B
then (perhaps in a detail
namespace).
Other alternatives include deriving from CMember
and inheriting its typedefs.