0

I have a following problem. I have these 3 files (I made a simplified example, but the errors are the same):

foo.hpp

#pragma once
#include <iostream>

class foo
{
protected:
    virtual void bar() const noexcept = 0;

public:
    foo() = default;
    virtual void callbar() = 0;
};

class baz : public foo
{
protected:
    void bar() const noexcept override;

public:
    void callbar();
};

foo.cpp

#include "foo.hpp"

inline void baz::bar() const noexcept { std::cout << "baz::bar()" << '\n'; }

inline void baz::callbar() { bar(); }

main.cpp

#include "foo.hpp"

auto main() -> int
{
    baz b;
    b.callbar();
}

Compiler (actually the linker I guess) gives me the following error:

foo.cpp
main.cpp
Generating Code...
Microsoft (R) Incremental Linker Version 14.15.26729.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:foo.exe
foo.obj
main.obj
main.obj : error LNK2001: unresolved external symbol "protected: virtual void __cdecl baz::bar(void)const " (?bar@baz@@MEBAXXZ)
main.obj : error LNK2019: unresolved external symbol "public: virtual void __cdecl baz::callbar(void)" (?callbar@baz@@UEAAXXZ) referenced in function main
foo.exe : fatal error LNK1120: 2 unresolved externals

Now I've gotten around this by doing either one of those two things:

  • Remove inline keyword
  • Leave inline as it is, but move the methods definitions to .hpp file

If I do one of those things, everything works. But my question is: why? In my real code I really wan the compiler to inline the method calls plus I want them to be defined in .cpp file, to make my .hpp file more clear. Is there a solution to that?

7
  • Why inline in definitions? Commented Apr 10, 2019 at 14:51
  • Well, I know if the method is defined entirely in class body then it's inlined by default, but if I define it outside, then it's not, and I want it to be. Cuz those methods will be called extremely often and I don't want to lose performance due to function call overhead Commented Apr 10, 2019 at 14:52
  • What do you think you getting by using inline? Removing the inline is the correct soution. Commented Apr 10, 2019 at 14:53
  • 1
    @dabljues You're misunderstanding what inline does. Surprisingly it has nothing to do with inlining functions. Commented Apr 10, 2019 at 14:53
  • Gosh, that's embarrassing. Now I know, thank you! Should I delete/close the question then? Commented Apr 10, 2019 at 14:58

1 Answer 1

3

Your code has a bug in it. According to cppreference

The definition of an inline function or variable (since C++17) must be present in the translation unit where it is accessed (not necessarily before the point of access).

Obviously, when you put your definitions in .cpp file and call those functions from other translation units, this condition is not satisfied.

So your two alternative approaches both work because they either

  • Remove this condition altogether (when you remove inline specifier)
  • Make the definition visible

And last, but not the least - C++ inline specifier has nothing to do with function inlining. There are other, compiler-dependent ways to request the actual inlining, i.e. __forceinline in various compilers.

Sign up to request clarification or add additional context in comments.

7 Comments

Thank you! This guy's answer, which @Aconcagua pasted: stackoverflow.com/a/5971755/1312382, suggests "Of course, this is in addition to the hint to the compiler that the function should be compiled inline into where it is used (avoiding a function call overhead).". So is he wrong then?
@dabljues yep, this is obsolete for a while. Compilers nowadays completely ignore inline when it comes to function inlining, and do it based on their own heuristics algorithms. Moreover, inlining is increasingly a property of a call site, rather than a function itself - function could be inlined in one place, and called in another.
Thank you, that was really clarifying!
@SergeyA compiler do actually still use inline declaration in their heuristics. And a function being inline has a lot to do with the function being inlined because it is not possible for the compiler to inline function calls across TU's. (although, it is possible for linkers).
@eerorika I still maintain that inline is a property of the language, rather than actual inlining. For example, a function which is not declared inline will still be inlined if it is's definition is visible, provided it is inlineable. The opposite is also true - an inline function which is not inlineable won't be inlined. Bottom line - the specifier is not related.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.