2

следующие работы в msvc2008 и MSVC2010 только что мелкие:Может ли встроенная функция вызова C++ объявлена ​​позже в заголовке?

class Foo { 
public: 
    static void FuncA(void) { 
    FuncB(); // "FuncB()" NOT DECLARED YET? WORKS, MSVC2008 
    } 
    static void FuncB(void); 
}; 

Да, это своего рода странно: FuncA() звонки FuncB(), даже если (на тот момент) FuncB() не-еще-заявлены. Однако MSVC2008 и MSVC2010 считают, что это нормально.

По-видимому, gcc не думаю, что это прекрасно - FuncB was not declared in this scope.

ВОПРОС: У меня их куча, и было бы «болью» объявить их, а затем определить их. Кроме того, было бы трудно «упорядочить» их должным образом, чтобы каждый из них только вызывал функции после того, как они были объявлены. Но, я предполагаю, что мне нужно объявить сначала-то-определить-позже?

Существуют ли разные правила, являются ли эти функции шаблонами или нет или определены в классе шаблонов или нет?

В частности, я заметил, что Microsoft очень «скомпонована», когда она принимает тонны взаимосвязанного кода, а LATER разрешает (при компиляции, когда запускается шаблонная параметризация), в то время как gcc, похоже, хочет compile сейчас, когда он «видит» код (начальный проход для правильности, и снова во время параметризации/вызова).

(Эта проблема показывает, как мы порта наш код Microsoft для Linux/GCC.)

=== UPDATE ===

Ниже приведены "альтернативные" сценарии, которые мы имеем (в это усиление кода), и будет ли ваш ответ изменяться на основе любого из них?

// Alternate-Scenario-B 
    class Foo2 { 
    public: 
     template<typename SOME_TYPE> 
     static void FuncA(const SOME_TYPE& some_type) { 
     FuncB(some_type); // "FuncB()" NOT DECLARED YET? WORKS, MSVC2008 
     } 
     template<typename SOME_TYPE> 
     static void FuncB(const SOME_TYPE& some_type); 
    }; 

... и:

// Alternate-Scenario-C 
    template<typename SOME_TYPE> 
    class Foo3 { 
    public: 
     static void FuncA(const SOME_TYPE& some_type) { 
     FuncB(some_type); // "FuncB()" NOT DECLARED YET? WORKS, MSVC2008 
     } 
     static void FuncB(const SOME_TYPE& some_type); 
    }; 

=== UPDATE + 2 ===

Спасибо за комментарии, где консенсус, кажется, что это справедливо C++ код, и должен работать (как предлагалось @Adam, функция «defined-inline» должна вести себя так, как если бы она была определена после класса, и должна иметь возможность вызывать функции, определенные в интерфейсе класса после этого встроенного определения).

Дополнительная информация:

Да, у меня действительно есть эта ошибка компиляции из первого примера в реализации FuncA() инлайн:

'FuncB' is not a member of 'Foo' 

... с помощью:

gcc (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2 

(Напомним, что это работает на MSVC2008/MSVC2010).

теперь я понимаю, что мой код-пример (выше) является недостаточным (в приведенном выше примере не показывает эту ошибку на gcc), вот еще некоторые детали:

  • Foo имеет базовый класс (I не думаю, что должно волновать)
  • Foo определяет внутреннюю enum который проходит через эти funcs (я не думаю, что это имеет значение)
  • эти функции «расширенные» через макрос (я думаю, что значительное - см ниже)
  • есть пятьдесят-шесть (56) из этих функций (я думаю, что значительное - см ниже)

Более полный пример кода будет (и я не горжусь этим):

#define FOO_FUNCS(CLASS_NAME,CLASS_ENUM) \ 
    static void FuncA(CLASS_ENUM value_enum) { \ 
    FuncB(value_enum); /*PROBLEM*/ \ 
    } \ 
    static void FuncB(CLASS_ENUM value_enum) { \ 
    FuncC(value_enum); \ 
    } \ 
    /*...THERE ARE 56 FUNCS IN THIS MACRO, THREE LINES EACH...*/ 

class Foo : public FooParent { 
    public: 
    enum FooEnum { FOO_ONE, FOO_TWO }; 
    FOO_FUNCS(Foo,FooEnum) // EXPAND THE 56 FUNCS 
}; 

КОД НАМЕРЕНИЯ: Базовый класс FooParent имеет реализацию, предназначенную для «совместного использования» (многими) производными классами. Производные классы определяют свои собственные значения enum. Функции, которые использовали эти значения enum, были реализованы с помощью макроса (поскольку FooParent не является template<> и не может полагаться на полученный enum).

Любопытный поведение:

  • Если FooA(){FooB();} вложенности ссылок функция, определенная «позже» лишь на «несколько линий», то gcc отлично компилируется. Однако, если еще не объявленная функция намного позже, например Foo2(){Foo53();}, то gcc делает вывод, что Foo53() не является членом класса (но это так).

Вот что я думаю, что происходит:

  • Там, кажется, проблема с большим-оф-кода (для 56 функций), которые физически на «одной линии». Если я выберу эти функции из макроса, И, если я удалю \ escape-line-endings, то gcc компилируется в порядке.

Таким образом, я думаю, что (код-портирование) Ответ:

  • не использовать препроцессор-макро
  • сделать класс FooParentBase<> шаблон, полученный из FooParent, из которого мы выводим Foo , которая требует typename Foo::enum в качестве шаблона-параметра

Я в порядке с этими изменениями (я не люблю макрос), но я нахожу это странным, что gcc, похоже, проблема.

Есть ли другие рекомендации, как это исправить? (Является ли вышеупомянутый перерасчет того, что вы бы сделали?)

+0

В вашем вопросе упоминаются шаблоны, но кода их нет. Возможно, вам нужен второй пример кода? –

+0

@Ben, спасибо, обновленный вопрос с примером 'template <>', но теперь я не думаю, что шаблоны являются частью проблемы (см. «UPDATE + 2») – charley

ответ

1

Ваш код выглядит совершенно законным для меня. Внутренние определения в определении класса должны рассматриваться как эквивалентные объявлениям с встроенным определением сразу после определения класса (к тому времени будет доступно объявление FuncB()).

Моя версия GCC принимает этот код как действительный (все три примера, которые вы публикуете, предполагая, что я предоставляю тривиальные реализации каждого FuncB(), конечно).

~$ g++ --version 
g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 
...

Я считаю, что дополнительная информация необходима здесь. Возможно, разместите свою версию GCC и определенное сообщение об ошибке, которое вы видите.

======== ОТВЕТ СПУСТЯ UPDATE =======

Я попробовал ваш последний пример с 70-функций в макро, и он все еще работает для меня gcc 4.6.3. Вот тест, который я пробовал (с макрос укороченным очевидным образом):

 
#include <iostream> 
using std::cout; 
struct FooParent { 
    static void Func71(int) { 
     cout << "Called\n"; 
    } 
};

#define FOO_FUNCS(CLASS_NAME,CLASS_ENUM) \ static void Func1(CLASS_ENUM value_enum) { \ Func2(value_enum); /PROBLEM/ \ } \ static void Func2(CLASS_ENUM value_enum) { \ Func3(value_enum); \ } \ /* Functions Func3...Func69 snipped */ \ static void Func70(CLASS_ENUM value_enum) { \ Func71(value_enum); \ } \ /...THERE ARE 70 FUNCS IN THIS MACRO, THREE LINES EACH.../

class Foo : public FooParent { public: enum FooEnum { FOO_ONE, FOO_TWO }; FOO_FUNCS(Foo,FooEnum) // EXPAND THE 70 FUNCS };

int main() { Foo::Func1(Foo::FOO_ONE); }

+0

Adam - отличная благодарность за это: проблема была проблемой с концом строки (это был проект по переносу кода, не знаю, как это получилось). Спасибо, что предоставили мне точку данных о том, что наша реализация должна работать. – charley

2

Все три из ваших сценариев правильные и скомпилированы как с g ++, так и с clang.

+0

+1 Я просто печатал то же самое. .. –

+0

Почему FuncB (some_type) не работает в сценарии-B? Не следует ли выводить тип параметра без использования списка аргументов шаблона? –

+0

@ AdamH.Peterson Вы правы. Я провел еще несколько тестов. –

Смежные вопросы