C ++内联函数调用函数可以在标题中稍后声明吗?

时间:2013-04-01 18:40:43

标签: c++ inline forward-declaration inline-code function-declaration

以下在MSVC2008和MSVC2010中使用 just-fine

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似乎当它“看到”代码时,想要编译 now (正确性的初始传递,以及参数化/调用期间的再次传递)。

(当我们将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有一个基类(我不认为这应该重要)
  • 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
};

CODE INTENT: FooParent基类的实现旨在由(许多)派生类“共享”。派生类定义自己的enum值。使用这些enum值的函数是通过宏实现的(因为FooParent不是template<>,并且不能依赖派生的 - enum)。

好奇的行为:

  • 如果FooA(){FooB();}嵌套引用“稍后”定义的函数只有“几行”,那么gcc编译就好了。但是,如果尚未声明的函数要晚得多,如Foo2(){Foo53();},那么gcc得出的结论是Foo53()不是类的成员(但它是)。< / LI>

以下是我的想法:

  • 似乎存在许多代码(对于56个函数)在物理上“单行”的问题。如果我从宏中取出这些函数, AND 如果我删除\转义行结尾,则gcc编译正常。

因此,我认为(代码移植)答案是:

  • 不要使用预处理器 - 宏
  • 制作一个源自FooParentBase<>的{​​{1}}模板类,我们从中FooParent派生Foo,这需要typename Foo::enum作为模板参数

我对这些变化很好(我不喜欢宏),但我发现gcc似乎在这里有问题我觉得很奇怪。

是否有其他建议如何解决此问题? (以上是否会重新考虑你会做什么?)

2 个答案:

答案 0 :(得分:2)

您的所有三个场景都是正确的,并使用g ++和clang进行编译。

答案 1 :(得分:1)

您的代码看起来非常合法。类定义中的内联定义应该被视为等同于紧跟在类定义之后具有内联定义的声明(此时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); }