user68723
user68723

Reputation:

Nested Template Specialization

Having a brain fart... Is it possible to make something like this work?

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

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

I don't have to do this, but it will allow me to nicely hide some implementation details from namespace scope.

Suggestions appreciated!

P.S.: I forgot to mention that explicitly specializing for Bar within Foo's scope isn't supported by the language. AFAICS, anyway.

Upvotes: 25

Views: 9528

Answers (7)

Hossein
Hossein

Reputation: 121

Clause 18, Section 14.7.3 of the 1998 standard (ISO14882:1998) says explicit specialisation of (the inner) template member classes is not allowed when the (outer) template class is not explicitly specialised.

Upvotes: 12

Michael Gazonda
Michael Gazonda

Reputation: 2864

Here's what I've been doing, which I think is simpler/more inline with what you're trying to do:

With Helper

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

OR - The helper can be removed if you don't mind doubling the specialization every time:

Without Helper

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

Upvotes: 1

mindriot
mindriot

Reputation: 5678

As others have pointed out, C++ doesn't let you specialize a nested class if the outer class template is not also specialized. When I had a situation like that, I was able to work around it with a helper class tucked away in an internal namespace:

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

Of course it's not quite as hidden as you might like it to be.

Upvotes: 0

Gabriel Schreiber
Gabriel Schreiber

Reputation: 2226

As the previous posters explained, this is not possible. You can however move the nested template into a non-template base class:

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

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

Upvotes: 0

Rob S
Rob S

Reputation:

Yes, you can. But you'll need to change the call structure, but just a little bit.

Specifically, use the strategy pattern to restructure the implementation of the member function as a class (which IS allowed to be specialized).

This is permitted as long as the strategy class is not nested (and hence not dependent on the unspecialized template type).

e.g. (this probably isn't syntactically correct, but the idea should be clear)

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

This is incredibly useful because calls to OuterThingThatIsNotSpecialized for types where no implementation exists will simply fail to compile.

PS. You can even use this strategy to partially specialize template functions, something that is an otherwise C++ impossibility.

Upvotes: 12

greyfade
greyfade

Reputation: 25677

You can't do that. I've tried many variations. This, however, compiles in GCC 4.1:

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

Edit (after reviewing the standard): If a is given, however, you can do this:

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

But not if Foo is not first specialized.

Upvotes: 0

coryan
coryan

Reputation: 1201

According to these posts:

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

you cannot specialize template members of a template class without specializing the outside class. They do not cite verse and chapter. My copy of "The C++ Programming Language" does not reveal anything immediately, and my copy of the standard is at home (my backup copy, better known here as "Chris" is not around either :-)

Upvotes: 3

Related Questions