Может ли C ++ встроить функцию вызова функции, объявленную позже в заголовке?

Следующие работы просто хорошо в MSVC2008 и MSVC2010:

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 кажется, хочет скомпилировать сейчас когда он «видит» код (начальный проход для корректности и снова во время параметризации / вызова).

(Эта проблема появляется, когда мы переносим наш код 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 предложил, функция «определенная-встроенная» должна вести себя так, как если бы она была определена после класса, и должна иметь возможность вызывать функции, определенные в интерфейсе класса после этого встроенного определения).

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ:

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

'FuncB' is not a member of 'Foo'

…с помощью:

gcc (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2

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

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

  • Foo имеет базовый класс (я не думаю, что это должно иметь значение)
  • Foo определяет внутренний enum который передается через эти функции (я не думаю, что это имеет значение)
  • эти функции «расширяются» с помощью макроса (я думаю, что значительный — см. ниже)
  • Есть пятьдесят шесть (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 функций), которые физически находятся на «одной строке». Если я возьму эти функции из макроса, А ТАКЖЕ если я удалю \ конец строки, затем gcc компилируется нормально.

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

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

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

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

2

Решение

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

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

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

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

======== ОТВЕТИТЬ НА ПОЗЖЕ ОБНОВЛЕНИЕ =======

Я попробовал ваш последний пример с 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); }

1

Другие решения

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

2

По вопросам рекламы [email protected]