内部类取决于模板参数

时间:2011-03-24 13:09:13

标签: c++ templates metaprogramming partial-specialization pimpl-idiom

考虑下一个例子:

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

使用g ++(版本4.3.0)编译时

g++ dfg.cpp  -ansi -pedantic -Wall

编译错误是:

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

我真正想要归档的是根据枚举值设置不同的Imp实现(在示例中,我使用int而不是枚举,但它应该无关紧要。)

有人可以解释为什么不允许这样做? 为什么我收到第一个错误? (这一个:限定名称不会在'{'标记之前)命名一个类


关于pimpl实现,取决于模板参数,我创建了一个新问题(更好的例子)here

2 个答案:

答案 0 :(得分:3)

这是无效的:

template< typename T >
struct B< 0, T >::C
{
    typedef T type;
};

可以专门化类模板的成员,但仅限于这些类模板的隐式实例化。这意味着用简单的英语:只有为封闭类模板的所有模板参数赋值(其成员需要专门化)。

template< >
struct B< 0, int >::C
{
    typedef T type;
};

您所写的是B<0, T>::C的定义,它是B<N, T>的类模板部分特化的成员。这样的部分特化不存在,因此,编译器出错了。


您有几种方法可以解决这个问题。一个是

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

请注意,显式特化(非局部)不能直接放入类模板中(因此,template<> struct CMember<0, int> { ... }B体内写入时会形成错误。您需要在B之外定义“选择器”模板(可能在detail命名空间中)。

其他替代方法包括从CMember派生并继承其typedef。

答案 1 :(得分:2)

您无法以C这种方式定义B - C您创建的B专精化不存在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; }; }; 。如果你想专门化B :: C,你需要专门化B.你是否想要做以下事情?

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

或者,您可以执行以下操作:

B<0, T>::C

这部分地将B专用于0并且转发声明C,以便可以定义{{1}}。