tags:

views:

430

answers:

3

We all know you can simulate closures in C++98 by defining local structs/classes inside a function. But is there some reason that locally defined structs can't be used to instantiate templates outside of the local scope?

For example, it would be really useful to be able to do things like this:

void work(std::vector<Foo>& foo_array)
{
    struct compareFoo
    {
       bool operator()(const Foo& f1, const Foo& f2) const
       {
         return f1.bar < f2.bar;
       }
    };

    std::sort(foo_array.begin(), foo_array.end(), compareFoo());
}

This would be especially useful if you know you're not going to need to use compareFoo anywhere else in your code. But, alas, this doesn't compile. Is there some reason that the compiler can't instantiate the std::sort template function using a locally defined struct?

+4  A: 

See GOTW #58 - you can't use locally defined classes as arguments to templated types, e.g. vector wouldn't be allowed.

From the C++ standard (14.3.1/2):

   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.  [Example:
    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
    }
   --end example]

Although I don't read this as meaning template functions like std::sort can't use a local class as an argument, apparently gcc thinks otherwise.

The local classes have no linkage (no global name), which seems like something that helps overburned compiler writers and hurts actual programmers. To actually allow a local class S to be used in vector<S> or some function<..,S>, I guess the generated thing would need a unique global name.

wrang-wrang
The standards text formatted as code looks interesting but not very readable :-)
rstevens
+1  A: 

The way I read the standard, it prohibits using local types as template parameters in general, which would mean both class and function templates.

It says: A local type ... shall not be used as a template-argument for a template type-parameter.

The example it gives uses a class template, but I suppose there's no reason to assume that this restriction is not applicable to template functions.

Anyway, I wonder what the reason for this restriction is. It seems arbitrary.

Charles Salvia
+4  A: 

There's no better reason than "it's not allowed by the standard".

I believe C++0x is going to lift this restriction, and allow you to use local classes as template parameters freely. But for now, it's not allowed.

jalf
Yep, C++0x will allow this and lambda expressions. About time.
wrang-wrang
I hurried up and looked for the two papers that fixed this issue for C++0x: The accepted one from 2008 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm and the not accepted one from 2007 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2402.pdf .
Johannes Schaub - litb