嵌套模板专业化

时间:2009-02-20 02:18:50

标签: c++ templates

有一个大脑放屁......是否有可能做出像这样的工作?

template<int a> struct Foo
{
    template<int b> struct Bar;
};

template<int a> struct Foo<a>::Bar<1> //Trying to specialize Bar
{
};

我没有来执行此操作,但它可以让我很好地隐藏命名空间范围内的一些实现细节。

建议赞赏!

P.S。:我忘了提到语言不支持明确专门针对Foo范围内的Bar。无论如何,AFAICS。

7 个答案:

答案 0 :(得分:12)

是的,你可以。但是你需要改变调用结构,但只需要一点点。

具体来说,使用策略模式将成员函数的实现重组为一个类(允许IS专门化)。

只要策略类没有嵌套(因此不依赖于非专用模板类型),就允许这样做。

e.g。 (这可能在语法上不正确,但这个想法应该是明确的)

template <class T>
class OuterThingThatIsNotSpecialized
{
  template <class U>
  void memberWeWantToSpecialize(const U& someObj_)
  {
    SpecializedStrategy<U>::doStuff(someObj_);
  }
};

template <class U>
struct SpecializedStrategy;

template <>
SpecializedStrategy<int>
{
  void doStuff(const int&)
  {
    // int impl
  } 
};

template <>
SpecializedStrategy<SomeOtherType>
{
  void doStuff(const SomeOtherType&)
  {
    // SOT impl
  } 
};

这非常有用,因为对没有实现的类型调用OuterThingThatIsNotSpecialized将无法编译。

PS。您甚至可以使用此策略来部分地专门化模板函数,这是C ++不可能实现的。

答案 1 :(得分:11)

1998年标准(ISO14882:1998)第18节第14.7.3节规定,当(外部)模板类未明确专门化时,不允许对(内部)模板成员类进行显式特化。

答案 2 :(得分:3)

根据这些帖子:

http://www.cpptalk.net/template-member-function-specialization-vt11666.html

如果没有专门化外部类,则无法专门化模板类的模板成员。他们不引用经文和章节。我的“C ++编程语言”副本没有立即显示任何内容,我的标准副本在家(我的备份副本,在这里更好地称为“Chris”不在其中: - )

答案 3 :(得分:1)

以下是我一直在做的事情,我认为这更简单/更符合您的尝试:

使用助手

template<int a> struct Foo
{
    template<int, int> struct Bar__;
    template<int b> using Bar = Bar__<b, b>;
};

template<int a> template<int b, int c> struct Foo<a>::Bar__
{
    // general case
    const static int x = 0;
};
template<int a> template<int b> struct Foo<a>::Bar__<b, 1>
{
    const static int x = 1;
};

int main(int argc, const char * argv[]) 
{   
    std::cout << Foo<1>::Bar<0>::x << "\r\n"; // general case - output 0
    std::cout << Foo<1>::Bar<1>::x << "\r\n"; // specialized case - output 1
    return 0;
}

或者 - 如果您不介意每次加倍专业化,可以删除助手:

没有助手

template<int a> struct Foo
{
    template<int b, int c> struct Bar;
};

template<int a> template<int b, int c> struct Foo<a>::Bar
{
    // general case
    const static int x = 0;
};
template<int a> template<int b> struct Foo<a>::Bar<b, 1>
{
    const static int x = 1;
};

int main(int argc, const char * argv[])
{   
    std::cout << Foo<1>::Bar<0, 0>::x << "\r\n"; // general case - output 0
    std::cout << Foo<1>::Bar<1, 1>::x << "\r\n"; // specialized case - output 1
    return 0;
}

答案 4 :(得分:0)

你做不到。我尝试了很多变化。然而,这个在GCC 4.1中编译:

template<int a> struct Foo
{
    template<int b> struct Bar;
    template<1> struct Bar;
};

编辑(审核标准后): 但是,如果给出了a,你可以这样做:

template <> template <> Foo<1> Bar<1>;

但如果Foo不是第一个专门的话,那就不行了。

答案 5 :(得分:0)

正如之前的海报所解释的那样,这是不可能的。但是,您可以将嵌套模板移动到非模板基类中:

struct FooBase
{
    template<int b> struct Bar;
}
template<int a> struct Foo : public FooBase
{
};

struct FooBase::Bar<1> // specializing Bar
{
};

答案 6 :(得分:0)

正如其他人所指出的,如果外部类模板也不是专用的,那么C ++不会让你专门化嵌套类。当我遇到这样的情况时,我能够使用隐藏在内部命名空间中的辅助类来解决它:

namespace internal {
  template <int a, int b> struct FooBarHelper
  { /* ... */ };
  // Specialization
  template <int a> struct FooBarHelper<a, 1>
  { /* specialized version goes here */ };
}

template<int a> struct Foo
{
  template<int b> struct Bar : public internal::FooBarHelper<a, b>;
};

当然,它并不像你希望的那样隐藏。