3

I can't get this to compile at all. I may not be possible but I don't know why it should not be.

class A {
  template <typename T> 
  class B {
   int test() { return 0; }
  };
  //template <> class B<int>; <-with this, namepace error
  B<int> myB_;
 };

 template <> class A::B<int> {
  int test() {
   return 1;
  }
 };

As it appears the compiler complains "The explicit specialization "class A::B" must be declared before it is used." If I try to provide the froward declaration in the commented line, the compiler complains "The explicit specialization "B" must be declared in the namespace containing the template." We use 2 different compilers here. This error is from IBM's "xl" compiler on AIX but I get similar errors with different verbage when compiling on our Sun systems. It seems like a catch-22.

Obviously, this is a highly contrived, simplistic example but, it represents the problem. I want to define a template class within a class because the template class is only relevent to the containing class. There should be no access to the template from outside the class.

Am I missing something?

user438938
  • 71
  • 4
  • Use four spaces to indent code (or select the code and press Ctrl+K). – Marcelo Cantos Sep 03 '10 at 12:57
  • This shouldn't compile as we see it even without specializations. But that's because were removed by the site confusing them with HTML tags. Please select code sections and mark them as such using the "101010" toolbar button when posting - that will preserve the code exactly as it is. Otherwise, specializing outside of the containing class is fine according to the standard. But please restore the missing parts of code for the discussion to be effective. – usta Sep 03 '10 at 13:05
  • With the situation you have with myB_, you might consider using the PIMPL idiom to not require B at that point. – usta Sep 03 '10 at 13:12

3 Answers3

3

You are correct. This is not possible to do (as far as I know). Your member declaration causes an implicit instantiation before the explicit specialization was declared. But how would you want to declare it? You cannot do that in class scope. Others have felt that this is an ugly restriction.

You could work around this by making the class member a pointer. This would not need to implicitly instantiate the class at that point, but rather at the point where you create the object in the end. I realize that this is an ugly work around. So better find other ways to do this.

For instance partial specializations are allowed in class scope. So you could add a dummy template parameter, then you can specialize this in the class before the member declaration. Likewise, i find this ugly, but it would not disturb things that much, I feel.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
0

You could work around the issue by using an unnamed namespace for privacy:

namespace {

  template <typename T> 
  class B {
   int test() { return 0; }
  };

  template <> class B<int> {
    int test() {
      return 1;
    }
};

}

class A {
  B<int> myB_;
};

This will compile, but if A needs to be visible outside this compilation unit, you'll need more elaborate machinery (e.g., interface and factory or Pimpl).

Greg Bacon
  • 134,834
  • 32
  • 188
  • 245
0

B is not a template class and you are trying to specialize it. That is the cause for the error. You can check these two errors C2913 and C3413. Is this what you are looking for?

class A
{
   template<class T>
   class B
   {
      inline int test()
      {
         return 0;
      }
   };
   A::B<int> myB_;
};
Gangadhar
  • 1,893
  • 9
  • 9