Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Does a template specialization need to be inline?

66 views
Skip to first unread message

Juha Nieminen

unread,
Feb 28, 2017, 9:26:44 AM2/28/17
to
Consider something like this:

template<typename> int foo() { return 1; }
template<> int foo<unsigned>() { return 2; }

If this is included in more than one compilation unit, does the latter
function need to be explicitly declared 'inline'?

Alf P. Steinbach

unread,
Feb 28, 2017, 10:47:41 AM2/28/17
to
Yes.

But you should be able to use that complete specialization just like an
ordinary function, with definition in one translation unit,

template<> int foo<unsigned>() { return 2; }

and just declaration in other translation units,

template<> int foo<unsigned>();

Disclaimer: I haven't tested that, and the ways of Bjarne are sometimes
mysterious.


Cheers!,

- Alf


Paavo Helde

unread,
Feb 28, 2017, 1:25:49 PM2/28/17
to
On 28.02.2017 17:47, Alf P. Steinbach wrote:
> On 2/28/2017 3:26 PM, Juha Nieminen wrote:
>> Consider something like this:
>>
>> template<typename> int foo() { return 1; }
>> template<> int foo<unsigned>() { return 2; }
>>
>> If this is included in more than one compilation unit, does the latter
>> function need to be explicitly declared 'inline'?
>
> Yes.
>
> But you should be able to use that complete specialization just like an
> ordinary function, with definition in one translation unit,
>
> template<> int foo<unsigned>() { return 2; }
>
> and just declaration in other translation units,
>
> template<> int foo<unsigned>();

In that case you need an explicit instantiation in the translation unit
containing the definition:

14/6: "A function template, member function of a class template,
variable template, or static data member of a class template shall be
defined in every translation unit in which it is implicitly instantiated
(14.7.1) unless the corresponding specialization is explicitly
instantiated (14.7.2) in some translation unit; no diagnostic is required."

It appears though that most implementations do not require the explicit
instantiation and appear to work fine without it (and with "no
diagnostic produced"). See the recent thread "does the language
guarantee `explicit specialization' will generate the code ?".


Alf P. Steinbach

unread,
Feb 28, 2017, 11:40:24 PM2/28/17
to
On 2/28/2017 7:25 PM, Paavo Helde wrote:
> On 28.02.2017 17:47, Alf P. Steinbach wrote:
>> On 2/28/2017 3:26 PM, Juha Nieminen wrote:
>>> Consider something like this:
>>>
>>> template<typename> int foo() { return 1; }
>>> template<> int foo<unsigned>() { return 2; }
>>>
>>> If this is included in more than one compilation unit, does the latter
>>> function need to be explicitly declared 'inline'?
>>
>> Yes.
>>
>> But you should be able to use that complete specialization just like an
>> ordinary function, with definition in one translation unit,
>>
>> template<> int foo<unsigned>() { return 2; }
>>
>> and just declaration in other translation units,
>>
>> template<> int foo<unsigned>();
>
> In that case you need an explicit instantiation in the translation unit
> containing the definition:
>
> 14/6: "A function template, member function of a class template,
> variable template, or static data member of a class template shall be
> defined in every translation unit in which it is implicitly instantiated
> (14.7.1) unless the corresponding specialization is explicitly
> instantiated (14.7.2) in some translation unit; no diagnostic is required."

Oh. So for Juha's example one formally needs

template<> int foo<unsigned>() { return 2; }
template foo<unsigned>();

Hurray for redundancy.


> It appears though that most implementations do not require the explicit
> instantiation and appear to work fine without it (and with "no
> diagnostic produced"). See the recent thread "does the language
> guarantee `explicit specialization' will generate the code ?".

I tried the following test code with g++ and MSVC:


[file "foo.hpp"]
#pragma once
template<class> int foo() { return 1; }
[/file]

[file "a.cpp"]
#include "foo.hpp"

template<> auto foo<unsigned>() -> int { return 2; }
#ifdef INSTANTIATE
template auto foo<unsigned>() -> int;
#endif
[/file]

[file "b.cpp"]
#include "foo.hpp"
#ifdef DECLARE
template<> auto foo<unsigned>() -> int;
#endif

#include <stdio.h>
auto main()
-> int
{
printf( "%d\n", foo<unsigned>() );
}
[file]


There are four possibilities: INSTANTIATE defined or not, and DECLARE
defined or not.

With both g++ and MSVC it was necessary to define DECLARE to avoid
linking error about multiple definitions.

And with both g++ and MSVC the same result, 2, was obtained regardless
of INSTANTIATE or not.


Cheers!,

- Alf

Mr Flibble

unread,
Mar 1, 2017, 1:23:47 PM3/1/17
to
You egregiously use 'auto' instead of 'int' for return type of main()
and then you go on to use printf (included from stdio.h instead of
cstdio) instead of cout? You need to have a serious word with yourself
Alf: your coding style and habits ARE TERRIBLE.

/Flibble



Alf P. Steinbach

unread,
Mar 1, 2017, 9:50:12 PM3/1/17
to
On 3/1/2017 7:23 PM, Mr Flibble wrote:
>
[snipped total over-quoting]

> You egregiously use 'auto' instead of 'int' for return type of main()

Nothing “egregiously” (bad) about that.

On the contrary, it's IMHO bad to needlessly mix two different syntaxes
for function declarations.

The old one has no advantages that I know of.


> and then you go on to use printf (included from stdio.h instead of
> cstdio) instead of cout?

Presumably you feel that there's some dissonance there.

The trailing return type syntax is only 6 years old, while `printf` is
like 40 years old. Is that it?

Sorry if I guess wrong about what you mean, but I'm not telepathic.


> You need to have a serious word with yourself
> Alf: your coding style and habits ARE TERRIBLE.

Well, you can help improve it. :) E.g., try to be clear about why one,
in your opinion, should never mix new stuff with old stuff, if that's
the point here? Because I just don't see it, it's not meaningful to me.


Cheers!,

- Alf

Mr Flibble

unread,
Mar 2, 2017, 1:05:24 PM3/2/17
to
First we can consider terseness:

int main() // 10 characters (including whitespace)
auto main() -> int // 18 characters (including whitespace)

Less characters can be grokked quicker by the brain.

Secondly we can consider rationale:

The trailing return type syntax was invented to solve a problem related
to templates and very few people think ALL functions should use it;
certainly not main() which is IDIOMATICALLY DEFINED.

You deliberately try to frustrate and irritate by obtusely writing legal
but obfuscated C++; why do you do this?

/Flibble

Alf P. Steinbach

unread,
Mar 2, 2017, 11:05:23 PM3/2/17
to
On 3/2/2017 7:05 PM, Mr Flibble wrote:
> On 02/03/2017 02:49, Alf P. Steinbach wrote:
>>
>> Well, you can help improve it. :) E.g., try to be clear about why one,
>> in your opinion, should never mix new stuff with old stuff, if that's
>> the point here? Because I just don't see it, it's not meaningful to me.
>
> First we can consider terseness:
>
> int main() // 10 characters (including whitespace)
> auto main() -> int // 18 characters (including whitespace)
>
> Less characters can be grokked quicker by the brain.

No doubt that is true in some situations.

And I agree that the most frequently used things should be shortest, as
a rule.

But `main` is not so much used that a few characters is a problem: in a
million function program there's only 1 `main`.


> Secondly we can consider rationale:
>
> The trailing return type syntax was invented to solve a problem related
> to templates

This is probably true. Wikipedia uses the example of letting the return
type be the promoted type of arguments. Andrei Alexendrescu wrote ¹an
article investigating how to do that properly for C++03, and it was
messy indeed – but then, C++03 didn't have `decltype`.


> and very few people think ALL functions should use it;

This is probably also true, just as very few people in the world, less
than 10%, think there is no supernatural deity or deities.

As religion to a large degree proves, the majority can't be counted on
to have an opinion that coincides with rational thinking for any given
question, until they've been convinced by non-rational arguments. In
particular, I believe, until they've been convinced that the rational
position is what people in their social group think. Then they're likely
to adopt the rational position, but not because it's rational.

At that point their opinion should /also/ be ignored. ;-)


> certainly not main() which is IDIOMATICALLY DEFINED.

Now this is rubbish, I'm sorry to tell you.

I think you mean that using the old syntax for declaring `main` is an
idiom, on account having been used exclusively for 40 years or so.

But an idiom in programming is a common way to do something, chosen from
/other possible ways/, and due to its frequent use probably a good
enough choice for most any situation. For example, the erase + remove
idiom in C++, as opposed to other ways of doing that, or the copy + swap
idiom for copy assignment operator implementation in C++, as opposed to
other ways of doing that. What other ways were there for the `main`
function syntax?


> You deliberately try to frustrate and irritate

And this telepathic insight into my motivations for whatever I do, is
also rubbish.

Don't trust your feelings, Leigh.


> by obtusely writing legal but obfuscated C++

And this is just not true as fact: it's probably your impression, and so
it's probably a true, heartfelt statement from you, but it's not true as
fact.


>; why do you do this?

Disregarding the inferred nefarious motivations for using trailing
return type, there remains the question of why you evidently perceive
code with trailing return type syntax to be “legal but obfuscated C++”.

I think you, who have this perception, is the only one who can answer that.


Cheers!,

- Alf

Links:
¹ <url: http://www.drdobbs.com/generic-min-and-max-redivivus/184403774>

Öö Tiib

unread,
Mar 3, 2017, 12:38:05 PM3/3/17
to
On Friday, 3 March 2017 06:05:23 UTC+2, Alf P. Steinbach wrote:
> On 3/2/2017 7:05 PM, Mr Flibble wrote:
>
> > and very few people think ALL functions should use it;
>
> This is probably also true, just as very few people in the world, less
> than 10%, think there is no supernatural deity or deities.
>
> As religion to a large degree proves, the majority can't be counted on
> to have an opinion that coincides with rational thinking for any given
> question, until they've been convinced by non-rational arguments. In
> particular, I believe, until they've been convinced that the rational
> position is what people in their social group think. Then they're likely
> to adopt the rational position, but not because it's rational.
>
> At that point their opinion should /also/ be ignored. ;-)

What a long way of saying that argumentum ad populum is a red herring
logical fallacy. :D It indeed would be fallacy if we could consider
coding style as something that can be logically proven to be better
or worse than other coding style.

However IMHO it can't. Source code is way of communication. Goodness
of its style is in most part in how appealing (or repulsive) it is for
other engineers who have to read it.


Juha Nieminen

unread,
Mar 6, 2017, 3:38:44 AM3/6/17
to
Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
> But `main` is not so much used that a few characters is a problem: in a
> million function program there's only 1 `main`.

In a million function program, how many of them need the trailing return
type syntax because the normal syntax doesn't suffice?
0 new messages