Почему код, использующий локальную структуру как параметр для функции STL, не компилируется в g++?

У меня есть такой код, который хорошо работает:

#include <algorithm>
#include <iostream>

char x[11]= "ABCDEFGHIJ";
char y[11];

struct F {
    char operator () (char c) const 
    { return c+1; }
};

int main()
{
    std::transform(x, x+10, y, F());
    y[10] = 0; std::cout <<y <<std::endl;
}

Но если я поменяю его на этот стиль:

#include <algorithm>
#include <iostream>

char x[11]= "ABCDEFGHIJ";
char y[11];

int main()
{
    struct F {
        char operator () (char c) const 
        { return c+1; }
    };
    std::transform(x, x+10, y, F());
    y[10] = 0; std::cout <<y <<std::endl;
}

Он не будет компилироваться, говоря:

error: нет соответствующей функции для вызова 'transform (char [11], char *, char [11], main():: F)

Что не так?

Версия gcc - 4.4, которая не распознает лямбда-выражения.

Ответ 1

В С++ - 98/03 второй код недействителен, так как F является локальным типом; в фактах, в §14.3.1.2 он заявил, что

Локальный тип, тип без привязки, неназванный тип или тип, составленный из любого из этих типов, не должны использоваться как шаблон-аргумент для параметра типа шаблона.

[Пример:

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] [Примечание: аргумент типа шаблона может быть неполным (3.9). ]

В С++ - 0x это ограничение удаляется; в этом же разделе новый стандартный черновик (N3126) явно показывает это в примере:

[Пример:

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
}

- конец примера] [Примечание: аргумент типа шаблона может быть неполным (3.9). - конечная нота]

Ответ 2

g++ 4.5.1 компилирует ваш код (с опцией -std=c++0x).

Второй образец кода плохо сформирован в С++ 03 1 но действителен в С++ 0x

std::transform является

template < class InputIterator, class OutputIterator, class UnaryOperator >
  OutputIterator transform ( InputIterator first1, InputIterator last1,
                             OutputIterator result, UnaryOperator op );

Однако g++ 4.4 не поддерживает локальные типы в качестве аргументов шаблона (даже с параметром - std=c++0x], поэтому вы получаете сообщение об ошибке.

1: Локальный тип, тип без привязки, неназванный тип или тип, составленный из любого из этих типов, не должны использоваться как шаблон-аргумент для параметра типа шаблона. (ISO С++ 03 §14.3.1.2)