Question

The following works just-fine in MSVC2008 and MSVC2010:

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

Yes, this is kinda weird: FuncA() calls FuncB(), even though (at that point) FuncB() is not-yet-declared. However, MSVC2008 and MSVC2010 thinks this is fine.

Apparently, gcc doesn't think this is fine -- FuncB was not declared in this scope.

ISSUE: I have a bunch of these, and it would be a "pain" to declare them, and later define them. Further, it would be hard to "order" them properly so each only calls functions after those were declared. But, I'm guessing I need to declare-first-then-define-later?

Are the rules different for whether these functions are template-or-not, or defined within a template-class or not?

Specifically, I've noticed Microsoft is very "late-compiling" where it accepts tons of inter-coupled code, and LATER resolves (at compile, when the template-parameterization is triggered), while gcc seems to want to compile now when it "sees" the code (an initial pass for correctness, and again during parameterization/invocation).

(This problem shows up as we port our Microsoft code to Linux/gcc.)

===UPDATE===

The following are "alternate" scenarios that we have (in this code-porting effort), and would your answer change based on any of these?

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

...and:

  // 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===

Thanks for the comments, where consensus seems that this is valid C++ code, and should work (as @Adam suggested, a function "defined-inline" should behave as if it were defined after the class, and should be able to call functions defined in the class interface after that inline definition).

MORE INFORMATION:

Yes, I really have this compile error from the first example in the FuncA() inline implementation:

'FuncB' is not a member of 'Foo'

...using:

gcc (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2

(Recall that this works on MSVC2008/MSVC2010).

I realize now that my code-example (above) is insufficient (the above example does not show this error on gcc), here are some more details:

  • Foo has a base-class (I don't think that should matter)
  • Foo defines an internal enum which is passed through these funcs (I don't think this matters)
  • these functions are "expanded" through a macro (I think significant -- see below)
  • there are fifty-six (56) of these functions (I think significant -- see below)

A more complete code example would be (and I am not proud of this):

#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: The FooParent base class has implementation that is intended to be "shared" by (many) derived classes. The derived classes define their own enum values. Functions that used these enum values were implemented through a macro (because the FooParent is not a template<>, and cannot rely upon the derived-enum).

Curious behavior:

  • If the FooA(){FooB();} nesting references a function defined "later" by only a "few-lines", then gcc compiles fine. However, if the yet-to-be-declared function is much later, like Foo2(){Foo53();}, then gcc concludes that Foo53() is not a member of the class (but it is).

Here's what I think is going on:

  • There seems to be an issue with lots-of-code (for 56 functions) that are physically on "one-line". If I take these functions out of the macro, AND if I remove \ escape-line-endings, then gcc compiles fine.

Thus, I think the (code-porting) answer is:

  • don't use a preprocessor-macro
  • make a FooParentBase<> template class derived from FooParent, from which we derive Foo, which requires the typename Foo::enum as a template-parameter

I'm fine with these changes (I didn't like the macro), but I find it weird that gcc seems to have an issue here.

Are there other suggestions for how to fix this? (Is the above re-factoring what you would do?)

Was it helpful?

Solution 2

Your code looks perfectly legal to me. Inline definitions within a class definition are supposed to be treated equivalent to declarations with an inline definition immediately following the class definition (by which time the declaration of FuncB() would be available).

My version of GCC accepts this code as valid (all three examples you post, assuming I provide trivial implementations of each FuncB(), of course).

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

I believe more information is needed here. Perhaps post your version of GCC and the specific error message you're seeing.

========REPLY TO LATER UPDATE=======

I've tried your latest example with 70 functions in the macro, and it's still working for me in gcc 4.6.3. Here is the test I tried (with the macro shortened in the obvious way):

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

OTHER TIPS

All three of your scenarios are correct and compile with both g++ and clang.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top