Juha Nieminen
unread,Sep 20, 2022, 5:49:17 AM9/20/22You do not have permission to delete messages in this group
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to
The standard states (if I understand correctly) that inline functions
with the same signature must have identical implementations, else
the behavior is undefined.
(In practice what will most likely happen if two different inline
functions have the same signature is that, in case they don't
actually get inlined and are instantiated on their own, the linker
will just choose one of the instances and drop the others. Which
means that code that was calling the others will now be calling
this one, likely to cause misbehavior, if the different versions
of this function weren't doing exactly the same thing.)
This got me thinking: I assume that, quite naturally, this requirement
extends to template functions (which are effectively "inline" by
default).
However, in this case it might be easier to create different
"inline" templated functions that have different implementations,
even though there's only one implementation in the source code
itself. The template function may produce different code depending
on the context.
I suppose that if it's the compiler itself that's producing different
code depending on the context in which the template is instantiated,
that doesn't really matter (because the programmer didn't do anything
wrong here; it's all on the compiler, well beyond the hands of the
programmer).
However, it might sometimes be easy to accidentally write templated
code that actually produces a different implementation depending on
the context in which the template is instantiated.
Suppose, for example, that the template function is something like:
template<typename T>
void foobar(const T& value)
{
std::cout << "The value is: " << value << "\n";
}
Now in some source file the programmer might be too clever for his
own good and actually overload the operator<< for a particular
type. Heck, there may be different overload implementations in
different source files.
However, it can get even subtler than that. For example, you could have
in some header something along the lines of:
const std::string kSomeString = "hello";
template<typename T>
void foobar(const T& value)
{
std::cout << kSomeString << ": " << value << "\n";
}
It might not be immediately apparent what the problem is. However, the
problem is that a const object has internal linkage by default, meaning
that the above std::string object is effectively the same thing as:
static const std::string kSomeString = "hello";
which in turn means that it will have its own unique instance in each
compilation unit where it's used. Which in turn means that the template
function will be pointing to a different object in each such compilation
unit. Which in turn means that, technically speaking, all these instances,
which have the same signature, have a different implementation.
"Who cares? All the string objects contain the same content. The end
result is the same."
Maybe. However, in some cases the thing outside the template function
might not be the same. Maybe what the std::string is initialized with
depends on which source code it is included into.