3

以下在 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

ISSUE: 我有一堆这些,声明它们然后定义它们会很“痛苦”。此外,很难正确地“排序”它们,因此每个函数都只在声明后调用函数。 但是,我猜我需要先声明,然后再定义?

这些函数是不是模板,还是在模板类中定义的规则是否不同?

具体来说,我注意到微软非常“后期编译”,它接受大量相互耦合的代码,并且稍后解析(在编译时,当模板参数化被触发时),而现在gcc似乎想要编译它“看到”代码(正确性的初始传递,并在参数化/调用期间再次传递)。

(当我们将 Microsoft 代码移植到 Linux/gcc 时,就会出现这个问题。)

===更新===

以下是我们拥有的“替代”场景(在此代码移植工作中),您的答案会根据其中任何一个而改变吗?

  // 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);
    };

===更新+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
};

代码意图:FooParent类具有旨在由(许多)派生类“共享”的实现。派生类定义它们自己的enum值。使用这些enum值的函数是通过宏实现的(因为FooParent不是 a template<>,并且不能依赖于派生的enum- )。

奇怪的行为:

  • 如果FooA(){FooB();}嵌套仅通过“几行”引用“稍后”定义的函数,则gcc可以正常编译。但是,如果尚未声明的函数要晚得多,例如Foo2(){Foo53();},则gcc断定它Foo53()不是类的成员(但它是)。

这是我认为正在发生的事情:

  • 物理上位于“单行”上的大量代码(用于 56 个函数)似乎存在问题。如果我将这些函数从宏中取出,并且如果我删除了\转义行结尾,那么gcc编译得很好。

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

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

我对这些更改很好(我不喜欢宏),但我觉得这里gcc似乎有问题很奇怪。

对于如何解决这个问题还有其他建议吗?(上面是否重新考虑了你会做什么?)

4

2 回答 2

2

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

于 2013-04-01T18:58:28.563 回答
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); }

于 2013-04-01T19:07:40.820 回答