2

考虑下一个例子:

#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 实现,我在这里创建了一个新问题(有更好的例子)

4

2 回答 2

3

这是无效的:

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

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

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

你写的是 a 的定义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。

于 2011-03-24T13:27:15.840 回答
2

您不能以这种方式C在外部定义 - 对于您正在创建的专业化不存在。如果您想专门化 B::C,则需要专门化 B。您是否尝试执行以下操作?BCB

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

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

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 并向前声明 C,因此B<0, T>::C可以定义。

于 2011-03-24T13:17:52.723 回答