3

I have defined a class Bar inside a member function (constructor) Foo, that I am trying to use as a template parameter.

template<typename Ty>
struct Spam {
    template<class U, class D> Spam(U*, D) {}
};
struct Foo {
    Foo() {
        struct Bar {};
        int *ptr = NULL;
        Spam<int> pSpam(ptr, Bar());
    }
};

My guess is that the usage is invalid as the scope of Bar is local to Foo and cannot have a global visibility which is required for template instantiation. But on a second though, I am instantiating the template in the same scope of Bar, and though the template class/struct is global, there should not be any accessibility issues of the template instance.

I tried across multiple compilers, and each behaves differently. Particularly

  • clang accepted with warning

    warning: template argument uses local type 'Bar' [-Wlocal-type-template-args]
    
  • VC++ compiled without warning

  • GCC 4.3.4 compilation failed

    10 : error: no matching function for call to 'Spam::Spam(int*&, Foo::Foo()::Bar)'
    3 : note: candidates are: Spam::Spam(const Spam&)
    
  • GCC C++14 compiled successfully

What is the expected behaviour according to the standards?

Abhijit
  • 62,056
  • 18
  • 131
  • 204
  • It should work, this is pretty similar as using a lambda (lambda is like a local class with operator() ), and using lambda as template parameter is really common. I don't know why it's not work with GCC 4.3.4, maybe it's a compiler bug or earlier it was restricted. – Melkon Sep 01 '15 at 08:03
  • 3
    http://stackoverflow.com/questions/5751977/local-type-as-template-arguments-in-c Here others say this was restricted before C++11, now it's legal. – Melkon Sep 01 '15 at 08:05
  • In C++03 you could not have [arguments with internal linkage](http://stackoverflow.com/a/23063914/1708801) but in C++11 it is allowed. – Shafik Yaghmour Sep 01 '15 at 09:15

1 Answers1

3

C++2003 standard 14.3.1/2 specify that

A local type, a type with no linkage, an unnamed type or a type compounded from any of these types shall not be used as a template-argument for a template type-parameter.

template <class T> class X { /* ... */ };
void f()
{
   struct S { /* ... */ };
   X<S> x3; // error: local type used as template-argument
   X<S*> x4;  // error: pointer to local type used as template-argument
}

But it is allowed in C++11 and higher.

N3797 14.3.1/2

template <class T> class X { };
template <class T> void f(T t) { }
struct { } unnamed_obj;
void f() 
{
   struct A { };
   enum { e1 };
   typedef struct { } B;
   B b;
   X<A> x1; // OK
   X<A*> x2; // OK
   X<B> x3; // OK
   f(e1); // OK
   f(unnamed_obj); // OK
   f(b); // OK
}
ForEveR
  • 55,233
  • 2
  • 119
  • 133