On Fri, Jan 14, 2011 at 05:39:58PM +0200, Achilleas Margaritis wrote:
> > [...]
> > There is a violation of the C++-standard:
> > - when main.cpp is compiled, the compiler reads "foo.hpp" -- and it
> > learns that the class "Foo" has a member-function "bar" which can be
> > call from within main.cpp -- so main.cpp is compiled without problem.
> > - when "foo.cpp" is compiled, the compiler does not read "foo.hpp" and
> > thus it sees that the function "bar" is defined INLINE. So the
> > compiler will NOT export Foo::bar() -- it will be impossible to
> > link to Foo::bar() from another compilation unit.
> > - finally, you try to link both compilation units. Result: main() tries
> > to call a function "Foo::bar()" -- but that does not exist ==>
> > compilation error.
> > On my machine, I get exactly that:
> > g++ main.cpp foo.cpp
> > /tmp/ccszFpug.o: In function `main':
> > main.cpp:(.text+0x27): undefined reference to `Foo::bar()'
> > collect2: ld returned 1 exit status
> [...]
> There is a solution to that: the compiler, knowing that foo::bar is
> not an inline function, it does not inline the function but it
> automatically compiles the relevant symbol in the foo.o object file.
I agree, one can solve it -- but with a change of the language. And for
example I use the fact that member-functions which are defined inline
ARE inline (e.g. to speedup trivial access functions).
>
> The trick is to let the compiler know that foo::bar is not an inline
> function. The information that foo::bar is not an inline function is
> contained in the header, as I've shown:
>
> foo.hpp:
> #ifndef FOO_HPP
> #define FOO_HPP
> #include <list>
> class Foo {
> public:
> void bar();
> };
> extern std::list<Foo *> foos;
> #endif //FOO_HPP
>
> So, if the compiler was informed about foo::bar not being inlined, it
> could then produce the appropriate symbol. This could happen if the
> autogenerated header is automatically included when the implementation
> file that produced the autogenerated header is compiled.
But that is not possible, as in this case you violate the C++-Standard:
Adding '#include "foo.hpp"' to foo.cpp in the example results in the
fact that class Foo is two times defined, which is illegal C++ -- and
in addition, the two definitions differ (once "bar" is inline, once it
isn't).
So the compiler would need to realize in addition that "foo.hpp" is an
autogenerated file -- and thus the compiler would have to use different
compilation rules.
>
> The compiler could check if there is an autogenerated header in the
> same folder as the implementation file; if there is, then it is
> included automatically in the implementation file.
>
> Then the compiler manages the clash of symbols as needed.
But with that everything becomes much more complex:
- When the compiler compiles "foo.cpp" -- how does he already know
that there is a "pragma autoinclude" in another file (here:
main.cpp)? Either you have to guarantee that "main.cpp" is compiled
before "foo.cpp" -- or you have to include the information "foo.hpp
will be autogenerated" also in the file "foo.cpp"
- How can the compiler detect that the file "foo.hpp" is autgenerated
-- and thus a different language-standard has to be used to treat
the class "Foo"? (allowing redefinition of the class; ignoring the
fact that the two class-definition differ, ...) -- just try adding
'#include "foo.hpp"' in the file foo.cpp, this results in:
g++ foo.cpp
foo.cpp:4: error: redefinition of ‘class Foo’
foo.hpp:6: error: previous definition of ‘class Foo’
- the code is no longer understandable by other compilers: it is
impossible to write by hand a "replacement header" with which an
unpatched compiler (without this new extension) could compile the
code (at least I don't see a possible way)
So I think, this extension would make it necessary at least:
- to change the language standard (and add special rules how classes
defined in an autogenerated-header are treated)
- to add also in "foo.cpp" the information that "foo.hpp" will be
autogenerated
- to mark "foo.hpp" as being autogenerated
And it will be impossible to compile such a code with another compiler
(which does NOT know those special rules), even if one supplies by hand
the generated header files.
Axel