On 1/17/2022 7:55 PM, James Kuyper wrote:
> On 1/17/22 7:28 PM, Andrey Tarasevich wrote:
> ...
>> Um... This is some rather strange wording: "use inline for the purpose
>> of violating the ODR rules". Where did you get this? ODR rules,
>> obviously, are aware of `inline` and inclusive of `inline`. Nobody's
>> talking about "violating" them here in any formal way.
>
> You're talking about 'inline' as a way of getting around those rules. If
> 'inline' didn't exist, then those rules obviously couldn't cite it as an
> exception, and what you're claiming is the primary purpose of 'inline'
> would be a violation of those rules. That purpose is expressed by
> inserting an exception for 'inline' into those rules.
When I'm talking about `inline` as an "ODR suppressor" or "defeater",
I'm not talking about the exact formal ODR as it is defined in C++
standard. I'm referring to the general/basic/primitive linker-level idea
of ODR: "if you have two identical symbols in you object files, you end
up with multiple definition error from the linker".
>> What I'm referring to is rather obvious from the above discussion.
>>
>> The primary purpose of the feature is this: the whole problem, the whole
>> objective is provide us with a feature, that would let us write
>>
>> unsigned foo = 42;
>>
>> void bar()
>> {
>> }
>>
>> in a header file and then include this file into multiple TUs.
>
> Declaring them with internal linkage would achieve the same benefit.
No it won't. In that case they won't have external linkage, meaning that
they will not refer to the same entity everywhere in the program. I
think I made it clear that this is part of the objective as well.
> ...
>> (`static` might be seen as workaround for the function, but we don't
>> want that. External linkage is the point here. For whatever reason, we
>> want a function with unique address identity for the whole program.)
>
> Why? I can imagine unusual circumstances where that might be needed, but
> I wouldn't expect it to be a common need.
For variables the common need is obvious. (I'm surprised I have to even
mention it.)
At the same time, I agree that for functions it is much less important
and common.
But if this were just about inline functions, chances are nobody would
even bother. However, in C++ the primary driver for this functionality
is not really inline functions at all. It is templates. 99.9% of the
pressing need for this "ODR suppressing" functionality comes from
templates. Implicit instantiation of templates faces the very same
issues: external linkage and multiple definitions, conflicting with the
"basic" idea of ODR I described above. Templates are the primary driver
behind that "gratuitously-overgenerate-then-discard" approach relied
upon by modern implementations.
(There were alternative implementations, intended to avoid
"overgeneration" and to play nice with "basic ODR", e.g. Sun Solaris C++
compiler, but AFAIK none of them survived.)
(C++ also provides you with facilities for explicit "manual"
instantiation of templates, which are, curiously, quite similar to C's
approach to `inline`. But I hope it is clear to everyone that C++
templates would never take off without their _implicit_ instantiation
mechanics.)
So, whether you consider inline functions with external linkage
necessary or not is not really that important. The
"gratuitously-overgenerate-then-discard" approach would still be there
anyway - for templates. And once it's there, you basically get inline
functions with external linkage for free, just for the sake of formal
completeness.
> Note that an inline function
> is only required to have a unique address if it has external linkage or
> module linkage (9.2.7p6). If having a single unique address was the main
> purpose of 'inline', why would it even be permitted to declare an inline
> function with internal linkage?
"Having a single unique out-of-line body" is probably better wording.
Having a single unique address naturally comes with it.
As for why inline functions with internal linkage are permitted...
There's simply no reason to prohibit it. `static inline` is redundant,
but there's no reason to spend effort to introduce a rule that would
prohibit it. There lots and lots of such redundant yet legal constructs
in C++.
> You could have functions with internal
> linkage if you don't need a unique address, and 'inline' functions, with
> inherently external linkage, if you do need a unique address. If that's
> the primary purpose, why didn't they it that way?
Again, that would lead to a more complicated specification of this
specifier without any tangible benefits. No need to do that.
Here's an immediately available example for you: variables again. Note
that `static inline` is _obviously_ redundant with namespace-scope
variables. There's no need to involve any "woulds", "whatifs" or
contrived scenarios here. `static inline` is obviously and
unconditionally redundant with variables today, right now, everywhere.
Yet, this is perfectly legal
/* Namespace scope */
static inline unsigned n = 42;
You can start asking your "why?" questions now. "Why do they allow
this?" "Why is it legal?" To me the answer is natural and obvious: why
not? No harm done, no need to overcomplicate things. This has always
been one of the cornerstone principles in thois language's design.