Ways to make inline work?

B

Barry

Hi, group

First, I write same cases I've already known, I don't concern that
specific compiler really do inline or not.
Please check them if they are right, and add the cases I miss

1.
// a.h
inline void f() {}

*inline*

2.
//a.h
inline void f();
//a.cpp
#include "a.h"
void f() {}

*NOT* inline, compiler just ignores the keyword

3.
// a.h
class A {
void f1() {}
inline void f2() {}
};

*inline*

4.
// a.h
class A {
inline void f2();
};

//a.cpp
#include "a.h"

void A::f() {}

*not* inline


5.
// a.h
class A {
void f();
};

//a.cpp
#include "a.h"

inline
void A::f() {}

*not* inline

6.
// a.h
class A {
void f();
};

inline void A::f() {}

*inline*

7.
//a.h
template <typename T>
class A {
void f1();
void f2() {}
};

template <typename T>
void A::f1() {}

*inline*

After so many examples,
I sum up from my humble experience, *inline* works when coming with the
function definition not the declaration. Is there any exception?

Like
// a.h
class A {
inline void f();
};

void A::f() {}

*inline*

thanks
 
A

Alf P. Steinbach

* Barry:
I sum up from my humble experience, *inline* works when coming with the
function definition not the declaration. Is there any exception?

Like
// a.h
class A {
inline void f();
};

void A::f() {}

*inline*

It seems you have some incorrect idea of what the "inline" keyword means
and how to use it.

"inline" allows you to define a given function with extern linkage, in
more than one compilation unit. In practice that's done by placing the
function definition in a header file, and that's also the practical
value, being able to define functions in header files (this was before
templates were introduced: templates provide a slightly more powerful
mechanism for the same, applying also to data). The mnemonic value of
that keyword is that the function's code is "inline" in the header file.

"inline" can be placed on a pure declaration or a definition.

A function declared (or defined) as "inline" must be defined in all
compilation units where it's used, and essentially it must be defined in
exactly the same way except for whitespace -- which is no problem when
the definition is provided by a reasonable header file.

Additionally, when a member function is defined within a class
definition, it's implicitly "inline", so there the "inline" keyword is
superflous.

And that's it.

Except that once upon a time "inline" also worked as an optimization
hint. However, modern compilers mostly just ignore that, and hinting is
a very unreliable form of communication anyway, prone to
misunderstandings. Using "inline" that way is not recommended.
 
J

James Kanze

"inline" allows you to define a given function with extern linkage, in
more than one compilation unit. In practice that's done by placing the
function definition in a header file, and that's also the practical
value, being able to define functions in header files (this was before
templates were introduced: templates provide a slightly more powerful
mechanism for the same, applying also to data). The mnemonic value of
that keyword is that the function's code is "inline" in the header file.

That's not really what the standard says. The standard
explicitly says "The inline specifier indicates to the
implementation that inline substitution of the function body at
the point of call is to be preferred to the usual function call
mechanism." Of course "to be preferred" is definitly not what
could be considered normative; the strictly normative effect is
to allow the function to be defined in more than one translation
unit. But a compiler which ignores the clearly stated intent of
the standard, without good reason, cannot be considered a good
compiler.

And templates, of course, have a completely different role; a
template function is not implicitly inline, and an inline
function is not a template.
"inline" can be placed on a pure declaration or a definition.
A function declared (or defined) as "inline" must be defined
in all compilation units where it's used, and essentially it
must be defined in exactly the same way except for whitespace
-- which is no problem when the definition is provided by a
reasonable header file.

Whitespace or comments (which are a form of whitespace, of
course). After preprocessing, of course. (The exact rules say
that the token sequence must be identical.) In addition, almost
all names must bind identically. (There is an exception for
constant data.) Something like:

inline T
f() { return 0 ; }

is illegal if in one compilation unit, T is a typedef for int,
and in another, a typedef for double.

Note that in practice, certain violations are common, and will
work. For example:

inline void
f( int i )
{
assert( i < 20 ) ;
// ...
}

Practically speaking, there will not be many modules compiled
with NDEBUG defined, but if there are any, then this formally
has undefined behavior, but in practice, won't cause any
problems.
Additionally, when a member function is defined within a class
definition, it's implicitly "inline", so there the "inline"
keyword is superflous.
And that's it.
Except that once upon a time "inline" also worked as an
optimization hint.

The standard, including the latest draft, says that that's what
it should do.
However, modern compilers mostly just
ignore that,

Are you sure? A good compiler will not ignore it, unless the
optimizer really is capable of doing a better job. Some are,
but not that many.
and hinting is a very unreliable form of
communication anyway, prone to misunderstandings.

Like register before it, it really doesn't apply at the right
level. It's all or nothing for a given function (or variable),
where as what you generally want is to inline just certain call
sites (or the variable in just certain blocks of code). There
are ways around this, but they are wordy and awkward, and almost
never used.

The main difference between inline and register is that today,
almost every compiler can do a better job at allocating
registers than the programmer, using the keyword register,
precisely because it does so locally. Whereas for inline, this
is still not the usual case. It's an ugly hack (because who
wants code in the header), but at times, it's the only solution.
Using
"inline" that way is not recommended.

Use of inline in general is to be avoided in header files. It
increases coupling. Similarly, non-exported templates should be
avoided. In both cases, however, if you're stuck, and don't
have a better alternative... (If the profiler says you've got
to, you've got to.)
 
A

Alf P. Steinbach

* James Kanze:
That's not really what the standard says.

That's meaningless unless you define what "that" refers to.

The standard says what I say in the first sentence. Relevant paragraphs
are §3.2/3 and §7.1.2/4. You looked at the wrong paragraph.

The standard does not address mnemonic values nor practical tool usage
(the rest of what I wrote above).

The standard
explicitly says "The inline specifier indicates to the
implementation that inline substitution of the function body at
the point of call is to be preferred to the usual function call
mechanism."

Yes, and it also says much else that is irrelevant to the correctness of
the above.

You're argumentative.

Of course "to be preferred" is definitly not what
could be considered normative; the strictly normative effect is
to allow the function to be defined in more than one translation
unit. But a compiler which ignores the clearly stated intent of
the standard, without good reason, cannot be considered a good
compiler.

And templates, of course, have a completely different role; a
template function is not implicitly inline, and an inline
function is not a template.

Again, unless you didn't grasp the distinction you're argumentative. I
wrote "mechanism for the same". The term "inline" has a very specific
meaning in the standard, and I didn't write that templates are "inline".
That's the less powerful mechanism.

In particular, if you want to define an extern linkage data item in a
header file that's included in multiple compilation units, "inline"
wont't work (it doesn't apply to data items), but the template mechanism
can do that for you.

And since I don't want more argumentative responses on this: the
standard's term for "compilation unit" is "translation unit".


[snipped more apparent-corrections-that-aren't]
The standard, including the latest draft, says that that's what
it should do.


Are you sure? A good compiler will not ignore it, unless the
optimizer really is capable of doing a better job. Some are,
but not that many.

I guess you can define the most used compilers as ungood and wiggle out
that way? Heh. :)

Like register before it, it really doesn't apply at the right
level. It's all or nothing for a given function (or variable),
where as what you generally want is to inline just certain call
sites (or the variable in just certain blocks of code). There
are ways around this, but they are wordy and awkward, and almost
never used.

The main difference between inline and register is that today,
almost every compiler can do a better job at allocating
registers than the programmer, using the keyword register,
precisely because it does so locally. Whereas for inline, this
is still not the usual case.

Let's concentrate on the "do a better job", and not the imagined reasons
for that (except your argument there is absurd: people can easily
analyze local effects, it takes a compiler to handle global ones).

And let's get concrete.

Like, g++, or Visual C++.

The behavior of g++ is partially discussed in <url:
http://gcc.gnu.org/onlinedocs/gcc/Inline.html>, where the two most most
relevant tidbits of information are that by default no inlining occurs,
and that g++ does not conform to the standard's requirement of using
"inline" in all compilation units. When you specify optimizations the
behavior depends on (1) keyword "inline" + non-standard ditto keywords,
(2) options for inlining, and there are a huge number of them, and (3)
the optimizer's judgement.

The behavior of Visual C++ is partially discussed in <url:
http://msdn2.microsoft.com/en-us/library/z8y1yy88(VS.80).aspx>, where
the most relevant info is that "The insertion (called inline expansion
or inlining) occurs only if the compiler's cost/benefit analysis show it
to be profitable.".

It's an ugly hack (because who
wants code in the header), but at times, it's the only solution.


Use of inline in general is to be avoided in header files.
Subjective.


It increases coupling.

In some cases, but mostly not.

Today, with template programming, many logical modules are implemented
as headers only.

As a concrete example, much of the usability of the Boost library stems
from it being mainly a header-only library.

The few logical modules that do require separate compilation are more
troublesome to use.

For such cases, /not/ using "inline" increases coupling, enormously,
namely to the separately compiled file.

Similarly, non-exported templates should be
avoided.

Now you have gone over the hill, James.

There's only one commercial compiler that officially supports "export".

Are you advocating using only the Comeau compiler, or are you joking?
 
J

Juha Nieminen

Alf said:
Additionally, when a member function is defined within a class
definition, it's implicitly "inline", so there the "inline" keyword is
superflous.

And that's it.

You forgot template functions: They are implicitly inline too.
 
J

James Kanze

* James Kanze:
That's meaningless unless you define what "that" refers to.

The paragraph immediately preceding. (I wasn't top posting, you
know.) The standard very explicitly says something about the
intent of inline, which you've chosen to ignore or deny.
The standard says what I say in the first sentence.

Amongst other things. That's only a partial picture. The first
half of the second sentence is also OK, but after that, it goes
downhill very quickly. What's the practical value of being albe
to define a function in a header? And how are templates in any
way relevant (except that they also allow definitions in a
header)? As a general rule, the less you put in a header, the
better.
Yes, and it also says much else that is irrelevant to the
correctness of the above.
You're argumentative.

And you're wrong, or at least, incomplete and misleading.
Again, unless you didn't grasp the distinction you're argumentative. I
wrote "mechanism for the same". The term "inline" has a very specific
meaning in the standard, and I didn't write that templates are "inline".
That's the less powerful mechanism.

I'll admit that I can't figure out what your point is here.
Unless it is that both templates and inline are broken, in that
they require additional information in the header, and thus
increase source code coupling. (In the case of inline, there is
a definite, technical motive. In the case of templates, it's
only because implementations don't care about implementing the
standard.)
In particular, if you want to define an extern linkage data item in a
header file that's included in multiple compilation units, "inline"
wont't work (it doesn't apply to data items), but the template mechanism
can do that for you.

So? You seem to have missed the point. You never want to do
anything like that, any more than you want to define a function
in a header. In the case of templates, you do it only because
you have to.
And since I don't want more argumentative responses on this:
the standard's term for "compilation unit" is "translation
unit".
[snipped more apparent-corrections-that-aren't]
The standard, including the latest draft, says that that's what
it should do.
Are you sure? A good compiler will not ignore it, unless the
optimizer really is capable of doing a better job. Some are,
but not that many.
I guess you can define the most used compilers as ungood and
wiggle out that way? Heh. :)

Actually, I was just considering the compilers I use. I know
that there are compilers which do ignore inline, because they
can do a better job. But they are still exceedingly rare. With
the compilers I use daily (g++ and Sun CC), it can certainly
make a difference, and is an important optimization tool.
And let's get concrete.
Like, g++, or Visual C++.
The behavior of g++ is partially discussed in <url:http://gcc.gnu.org/onlinedocs/gcc/Inline.html>, where the two most most
relevant tidbits of information are that by default no inlining occurs,
and that g++ does not conform to the standard's requirement of using
"inline" in all compilation units. When you specify optimizations the
behavior depends on (1) keyword "inline" + non-standard ditto keywords,
(2) options for inlining, and there are a huge number of them, and (3)
the optimizer's judgement.

In sum, the compiler doesn't ignore inline, unless you tell it
to.

FWIW: I've actually had to use inline with g++ on one or two
occasions, for optimization reasons. It measurably makes a
difference. And you cannot get more concrete than that.
The behavior of Visual C++ is partially discussed in <url:http://msdn2.microsoft.com/en-us/library/z8y1yy88(VS.80).aspx>, where
the most relevant info is that "The insertion (called inline expansion
or inlining) occurs only if the compiler's cost/benefit analysis show it
to be profitable.".

Which means?
Subjective.

Build times are not subjective.
In some cases, but mostly not.

Are you kidding?
Today, with template programming, many logical modules are
implemented as headers only.

Today, because of the coupling templates imply (in the absence
of compilers implementing export), most shops very strictly
limit their use. They have a significant cost. For low level
things, like the standard containers, the advantages outweigh
the cost, but at the application level, that's rarely the case.
As a concrete example, much of the usability of the Boost
library stems from it being mainly a header-only library.

The fact that it's mainly header-only is a major disadvantage,
and does limit its use somewhat. But considerations for third
party libraries (reputed stable) are different than those for
application code. If I upgrade the compiler, or something like
Boost, I do a complete rebuild anyway. (But of course, it's
something that you typically don't want to have to do more than
once every two or three years.)
The few logical modules that do require separate compilation
are more troublesome to use.

In the case of Boost, that's because they use a hopelessly
broken build system.
For such cases, /not/ using "inline" increases coupling,
enormously, namely to the separately compiled file.

Now you're being silly. Do you know what coupling means?
Now you have gone over the hill, James.
There's only one commercial compiler that officially supports "export".
Are you advocating using only the Comeau compiler, or are you joking?

Actually, I'm advocating avoiding overuse of templates. For
extremely stable, third party libraries, fine. For application
code, no.
 
A

Alf P. Steinbach

* James Kanze:
[snipped unclear stuff]
Actually, I'm advocating avoiding overuse of templates. For
extremely stable, third party libraries, fine. For application
code, no.

If "non-exported" didn't mean anything, then you wrote "templates should
be avoided".

Oh well.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,997
Messages
2,570,240
Members
46,829
Latest member
KimberAlli

Latest Threads

Top