【问题标题】:specialize a member template without specializing its parent专门化成员模板而不专门化其父模板
【发布时间】:2010-01-05 23:25:12
【问题描述】:

我有一个嵌套在另一个模板中的类模板。部分特化很容易:我只是在其父级中声明另一个 template< … > 块。

但是,我需要另一个偏特化来指定其所有本地模板参数。这使它成为一个明确的专业化。无论出于何种原因,显式特化必须在命名空间范围内。要在其父类之外声明它,必须指定父类,这需要一个非空的模板参数列表。这意味着部分专业化。部分专业化我正在做的事情,它应该在任意外部范围内工作。但是 GCC 和 Comeau 都无法使用偏特化形式参数识别父提名中的模板参数。

template< class X > struct A {
    template< class Y > struct B; // initial declaration OK

    template< class Z >
    struct B< A< Z > > {}; // partial OK as long as there's a local arg

    template<> // ERROR: this syntax triggers explicit specialization
    struct B< int > {};
};

template<> // ERROR: can't nest template<>s here (why?)
template< class X > // ERROR: can't deduce X from type of A<X>::B<int> (why?)
struct A< X >::B< int > {};

(我把我所有的非工作代码都留在了;适当地注释它以试图理解。)

【问题讨论】:

  • 顺便说一下,您可以通过添加一个虚拟参数来解决它,例如int,它始终是0。这是我第一次玩 C++0x;我正在尝试遍历tuple。我以前做过这种事情,令人讨厌的是 C++0x 的tuple 不如 Boost 的强大……遍历模板参数是有用的功能,不应该成为一种仪式。哦,尽管我解决了所有的错误,但 GCC 仍然是 ICE。

标签: c++ templates partial-specialization


【解决方案1】:

在 C++ 标准 14.7.3/18 下是非法的:

.... 声明不应显式特化类成员 模板,如果它的封闭类模板没有明确专门化 也是。

【讨论】:

  • 谢谢!我知道我以前经历过这个,因为它适用于所有模板递归。
【解决方案2】:

我倾向于不过多地使用嵌套类。我的主要抱怨是他们倾向于使嵌套类的代码膨胀。

因此我会提出另一种解决方法:

namespace detail
{
  template <class X, class Z> class BImpl;
  template <class X, class Z> class BImpl<X, A<Z> > {};
  template <class X> class BImpl<X,int> {};
}

template <class X>
class A
{
  template <class Z> struct B: BImpl<X,Z> {};
};

请注意,如果您还希望专门化 A,则需要将 X 作为参数传递给 BImpl。有趣的是,在这种情况下,我最终只获得了部分专业化!

【讨论】:

  • 是的。我更喜欢臃肿的类,而不是带有friends 的臃肿外部表示……代码总量是相同的,或者嵌套更少。在这种特殊情况下,父类有一个 C++0x 可变参数列表,它试图将一个子集传递给子类,因此它也是可变参数的。因此,无法将所有父母的论点传递给孩子/朋友,但又明确地专门针对孩子/朋友的某些情况。
【解决方案3】:

复杂的东西。你的初始代码 ICE 的 VC10 Beta2,不错。

首先,我认为你有这个倒退:

template<> 
template< class X > 
struct A< X >::B< int > {};

X 是结构 A 的模板参数,而 B 是完全专用的,所以我认为应该是这样的:

template< class X > 
template<> 
struct A< X >::B< int > {};

但即使这样也无法编译。不过,错误文本实际上很有用:

a.cpp a.cpp(11):错误 C3212: 'A::B' :显式 模板成员的特化 必须是显式的成员 专业化 a.cpp(8) : 参见 'A::B' 的声明

如果你也完全专门化 A,那么完全专门化 B 似乎是合法的。

编辑:好的,我收到了可以对此发表权威意见的人的回复 - 换句话说,这是标准中一个非常模糊的区域,这是 C++ 委员会要清理的未解决问题it up(“it”是类模板成员的显式特化)。在短期内,建议是“不要那样做”。

【讨论】:

  • 是的,我注意到我将嵌套参数列表“向后”发布;我尝试了两种方法,直到我生病了。一种方式是它看不到 X,另一种方式是它抱怨明确的内部部分。当然,还取决于使用的编译器。该标准对这些东西非常模糊和杂乱无章,但我看不出它有任何非法的理由。
  • 我明白了。我不是语言律师(虽然我有时会在互联网上玩)——但 VC10 高度合规,所以如果它告诉我某事是非法的,我倾向于相信它。希望其他人可以加入描述这种行为的语言。
【解决方案4】:

至少这在 VC 2010 中有效。但是,我无法编写 def。类声明之外的“int”的fun()。 编辑:不幸的是 g++ 也有编译问题。 编辑:下面的代码适用于 VC 2010。

template<typename X>
class A
{
public:
    A()
    {

    }

    template<typename Y>
    struct B
    {
        void fun();
    };

    template<>
    struct B<int>
    {
        void fun()
        {
            cout << "Specialized version called\n";
        }
        //void fun();
    };



public:

    B<X> b;
};



template<typename X>
template<typename Y>
void A<X>::B<Y>::fun()
{
    cout << "templated version called\n";
}

int main()
{
   A<int> a;
    a.b.fun();
    A<float> a1;
    a1.b.fun();
}

【讨论】:

  • 很高兴知道。我会说编译器不应该都支持这一点没有的理由。无论如何,我不想在课外写定义。但是,当然,这是我尝试的第一件事……
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多