In the c++ standard [temp.point] it is written:
The instantiation context of an expression that depends on the
template arguments is the set of declarations with external linkage
declared prior to the point of instantiation of the template
specialization in the same translation unit.
Then in [temp.dep.candidate]:
For the part of the lookup using associated namespaces
([basic.lookup.argdep]), only function declarations found in either
the template definition context or the template instantiation context
are found.
Does it means that the following code should fail:
namespace A{
struct S{};
}
template<class T>
void g(T a){
f(a); //f will be found by argument dependent lookup
}
namespace A{
static void f(S); //but f doesn't have external linkage
}
void test(A::S i){
g(i);
}
//point of instantiation of g
//A::f(S) doesn't have external linkage
//=> so it's not in the instantiation context of template g ??
This code actually compiles, so what does this standard paragraph mean?
This is a defect in the standard. Originally addressed in core issue 561, where the committee judged that
Notes from the April, 2006 meeting:
The consensus of the group was [..] that internal-linkage functions should be found by the lookup (although they may result in errors if selected by overload resolution).
Unfortunately the corresponding fix was insufficient, as elaborated in core issue 1258:
C++11 expanded the lookup rules for dependent function calls (17.7.4.2 [temp.dep.candidate] paragraph 1 bullet 2) to include functions with internal linkage; previously only functions with external linkage were considered. However, 17.7.4.1 [temp.point] paragraph 6 still says,
The instantiation context of an expression that depends on the template arguments is the set of declarations with external linkage declared prior to the point of instantiation of the template specialization in the same translation unit.
Presumably this wording was overlooked and should be harmonized with the new specification.
That is, the previous wording of your second quoted paragraph was
For the part of the lookup using associated namespaces (3.4.2), only function declarations with external linkage
found in either the template definition context or the template instantiation context are found.
.. which was amended for C++11, but that change missed your first quote, making it rather pointless. The intent is that functions with internal linkage are not discriminated.
Related
This description on cppreference.com says that
The lookup of a dependent name used in a template is postponed until the template arguments are known, at which time [...] ADL examines function declarations with external linkage that are visible from either the template definition context or the template instantiation context.
Contrary to this the following code snippet compiles fine with three compilers (MSVC, clang, gcc):
template <class T>
void CallFoo ()
{
Foo (T ());
}
class Apple {};
int main ()
{
CallFoo<Apple> ();
}
static void Foo (Apple)
{
}
Foo is a dependent name in CallFoo: it depends on template argument T. But the function Foo is found by the compiler despite violating two of the above quoted rules.
The declaration of Foo is not visible from either the definition or instantiation of CallFoo, because it is below both.
Foo has internal linkage.
It is unlikely, that all three compilers have a bug. I might have misunderstood something. Could you elaborate on this?
In C++03, members of anonymous namespaces could have external linkage despite being unnameable in other translation units. It was therefore thought permissible to preclude actual static functions from dependent ADL. In C++11, anonymous namespaces impose internal linkage, so the restriction became unreasonable. However, despite implementations adopting the new behavior and an issue being filed immediately in 2011 (as noted in the comments), the wording remained in two places until N4810 in March 2019.
As for the placement of the function, this is an artifact of functions having multiple points of instantiation, including the end of any translation unit that instantiates them (with slight adjustments for modules in C++20); if instantiating the function template produces different results for different choices, the program is ill-formed, no diagnostic required (as also noted in the comments).
I stumbled on this the other day and can't figure out which answer is correct, or whether both are acceptable.
Specifically, I'm referring to the call to bar(T{}) in OtherFunction. From what I've been able to test on compiler explorer, the decision seems split. msvc and icc agree that it is ambiguous while gcc and clang compile the code without issue.
The function bar inside the namespace hidden becomes visible through argument-dependent lookup. Additionally, msvc/icc consider the declaration of bar in the global namespace as a candidate while gcc/clang do not. It seems that the declaration in the global namespace should not be considered since it is declared after the call to bar(T{}) but I'm not sure whether I'm reading the rules for unqualified name lookup correctly or if the standard is ambiguous in this regard.
https://godbolt.org/z/HAS-Cv
EDIT:
Looks like msvc has fixed this as long as /permissive- option is used
(https://devblogs.microsoft.com/cppblog/two-phase-name-lookup-support-comes-to-msvc/)
template <typename T>
inline void OtherFunction () {
bar(T{});
}
namespace hidden {
struct Foo {};
inline void bar (Foo foo) {}
}
inline void bar (hidden::Foo foo) {}
void Function () {
OtherFunction<hidden::Foo>();
}
Gcc and Clang are correct. The global bar defined after the definition of OtherFunction can't be found by name lookup; while hidden::bar could be found by ADL.
(emphasis mine)
For a dependent name used in a template definition, the lookup is postponed until the template arguments are known, at which time ADL examines function declarations with external linkage (until C++11) that are visible from the template definition context as well as in the template instantiation context, while non-ADL lookup only examines function declarations with external linkage (until C++11) that are visible from the template definition context (in other words, adding a new function declaration after template definition does not make it visible except via ADL).
The code is valid, so msvc and icc are incorrect.
Since an argument of bar is type-dependent, the name bar is a dependent name, and is looked up only when the template OtherFunction is instantiated, not when the template is defined.
C++17 [temp.dep.candidate]/1:
For a function call where the postfix-expression is a dependent name, the candidate functions are found using the usual lookup rules ([basic.lookup.unqual], [basic.lookup.argdep]) except that:
For the part of the lookup using unqualified name lookup ([basic.lookup.unqual]), only function declarations from the template definition context are found.
For the part of the lookup using associated namespaces ([basic.lookup.argdep]), only function declarations from either the template definition context or the template instantiation context are found.
So jumping to [basic.lookup.argdep]/3:
Let X be the lookup set produced by unqualified lookup ([basic.lookup.unqual]) and let Y be the lookup set produced by argument dependent lookup (defined as follows). If X contains
a declaration of a class member, or
a block-scope function declaration that is not a using-declaration, or
a declaration that is neither a function nor a function template
then Y is empty. Otherwise Y is the set of declarations found in the namespaces associated with the argument types as described below. The set of declarations found by the lookup of the name is the union of X and Y.
[The current C++20 draft has rearranged wordings in these sections. In particular, the rule about including the instantiation context for lookup of a dependent name in associated namespaces is now listed in [basic.lookup.argdep]/4.5, and is just a Note in [temp.dep.candidate]. I'm not sure if the reason for this is just for clarity, or might have something to do with effects of modules.]
X is the result of unqualified lookup for the name bar considering only declarations visible from the template definition context. But since the template definition context is the very beginning of your translation unit, obviously X is empty.
Since X doesn't contain anything at all, it doesn't contain the listed items which would force Y to be empty. So to determine Y, we look in the namespaces associated with the argument types. The argument type in this instantiation is hidden::Foo, so the only associated namespace is hidden, and the single result of name lookup is function hidden::bar.
::bar is not visible in this name lookup, so the bar(T{}) expression cannot be ambiguous.
If I will write something like this:
// A.h
#ifndef A_h
#define A_h
class A
{
public:
void f();
};
void A::f()
{
}
#endif //A_h
// B.cpp
#include "A.h"
void foo()
{
A a;
a.f();
}
// C.cpp
#include "A.h"
void bar()
{
A b;
b.f();
}
// main.cpp
#include "B.cpp"
#include "C.cpp"
using namespace std;
int main()
{
foo();
bar();
return 0;
}
I get a linker error as such:
error LNK2005: "public: void __thiscall A::f(void)" (?f#A##QAEXXZ)
already defined in B.obj
Why does the same problem not happen when the A class is a class template? Eventually it becomes a plain class (a non-template one) during compilation, right? For this reason, I expect the same behavior as a non-template class, i.e. a linker error.
There are two separate effects at work here:
A member function definition that's out of line is a normal function definition, and by one definition rule (ODR) it must occur precisely once in the link. A member function defined inline is implicitly inline, and the ODR allows inline function definitions to be repeated:
That is, it's OK to put the following code in a header and include it repeatedly:
struct Foo {
void bar() {} // "inline" implied
};
But if you have the definition out of line, it must be in a single translation unit.
Function templates can be defined repeatedly, even when they are not inline. The templating mechanism in general already needs to deal with repeated instantiations of templates, and with their deduplication at link time.
Member functions of class templates are themselves function templates, and therefore it doesn't matter whether you declare them inline.
Why is it that the non template functions are treated differently to templates when it comes to multiple definitions?
There are historical and compatibility issues involved here. Some of the requirements come from C, that is the way it worked. There are also reasons related to what templates are, they are code generators; when required, the compiler needs to generate the code, consequently it needs to see the code when it generates it. This has a knock on effect that there will be multiple definitions, so rules are required to resolve those issues.
Simply put; templates behave (w.r.t. linking) as if they had a single definition in the program, hence they do not behave the same during compilation and linking as non-templates (that are not declared with inline) - in particular w.r.t. functions. If the non-templates are declared inline, similar behaviour is seen.
Standard references here include;
Some background, most of the issues here relate to linkage, what is linkage? §3.5/2 [basic.link]
A name is said to have linkage when it might denote the same object, reference, function, type, template, namespace or value as a name introduced by a declaration in another scope:
When a name has external linkage, the entity it denotes can be referred to by names from scopes of other translation units or from other scopes of the same translation unit.
When a name has internal linkage, the entity it denotes can be referred to by names from other scopes in the same translation unit.
When a name has no linkage, the entity it denotes cannot be referred to by names from other scopes.
Some general rules relating to functions and variable, for the program as a whole and each of the translation units.
§3.2/1 [basic.def.odr]
No translation unit shall contain more than one definition of any
variable, function, class type, enumeration type, or template.
And
§3.2/4 [basic.def.odr]
Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program...
§3.2/6 [basic.def.odr]
There can be more than one definition of a class type (Clause [class]), enumeration type ([dcl.enum]), inline function with external linkage ([dcl.fct.spec]), class template (Clause [temp]), non-static function template ([temp.fct]), static data member of a class template ([temp.static]), member function of a class template ([temp.mem.func]), or template specialization for which some template parameters are not specified ([temp.spec], [temp.class.spec]) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements....
If D is a template and is defined in more than one translation unit, then the preceding requirements shall apply both to names from the template's enclosing scope used in the template definition ([temp.nondep]), and also to dependent names at the point of instantiation ([temp.dep]). If the definitions of D satisfy all these requirements, then the behavior is as if there were a single definition of D. If the definitions of D do not satisfy these requirements, then the behavior is undefined.
Some informal observations on the above list including the classes, templates etc. These are typical elements often found in header files (of course not exclusively or limited to headers). They are given these special rules to make everything work as expected.
What about class member functions? §9.3 [class.mfct]
1/ A member function may be defined ([dcl.fct.def]) in its class definition, in which case it is an inline member function ([dcl.fct.spec]), or it may be defined outside of its class definition if it has already been declared but not defined in its class definition. A member function definition that appears outside of the class definition shall appear in a namespace scope enclosing the class definition...
2/ An inline member function (whether static or non-static) may also be defined outside of its class definition provided either its declaration in the class definition or its definition outside of the class definition declares the function as inline or constexpr. [ Note: Member functions of a class in namespace scope have the linkage of that class. Member functions of a local class ([class.local]) have no linkage. See [basic.link]. — end note ]
So basically, member functions not defined in the class definition and not implicitly inline, hence the "normal" rules apply and hence can only appear once in the program.
And template, what does it say about linkage ? §14/4 [temp]
A template name has linkage ([basic.link]). Specializations (explicit or implicit) of a template that has internal linkage are distinct from all specializations in other translation units... Template definitions shall obey the one-definition rule ([basic.def.odr]).
Templates are not code; they are patterns for creating code. They must be visible wherever they are used, so the compiler has to have special rules for using them. The key special rules here are that the compiler generates code wherever a template is used and that the linker ignores duplicates.
I understand that a template cannot appear inside an extern "C" block, the reason for which is that the name of the instantiated template functions cannot appear once than once using an unmangled name.
However, in the code below, the name of the function is being mangled (so there should be no problem because each instantiation will have a unique name) but still has function type with C language linkage. My question is whether the code below is well formed:
extern "C" using fn_type = void();
template<typename T>
fn_type foo;
int main()
{
fn_type* const p = foo<int>;
p();
}
Edit: it is hard to test if this is conforming just by running it through a compiler because GCC, Clang and MSVC don't distinguish between C++ and C function pointer types.
To me, the standard does not seem 100% clear on this. The only relevant part which mentions templates and linkage is C++11, [temp]§4:
A template name has linkage (3.5). A non-member function template can have internal linkage; any other template name shall have external linkage. Specializations (explicit or implicit) of a template that has internal linkage are distinct from all specializations in other translation units. A template, a template explicit specialization (14.7.3), and a class template partial specialization shall not have C linkage. Use of a linkage specification other than C or C++ with any of these constructs is conditionally-supported, with implementation-defined semantics. [...]
(Emphasis mine)
The paragraph starts with template names having linkage. Then it says "funciton template (notname) can have internal linkage; any other template name shall have external linkage."
To me, this seems to imply referring to the linkage of a template refers to the linkage of the template's name. If that interpretation is correct, then your example is well-formed, as the bolded part would apply to template names as well. Then nothing prevents function template types from having C linkage.
That's how I would interpret the standard.
Background
In C++03, symbols used as template arguments must have external linkage; this restriction was removed in C++11, as explored in this previous question:
In C++03, template arguments could not have internal linkage:
[C++03: 14.6.4.2/1]: For a function call that depends on a template parameter, if the function name is an unqualified-id but not a template-id, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2) except that:
For the part of the lookup using unqualified name lookup (3.4.1), only function declarations with external linkage from the template definition context are found.
For the part of the lookup using associated namespaces (3.4.2), only function declarations with external linkage found in either the template definition context or the template instantiation context are found.
[..]
This was changed (issue #561: "Internal linkage functions in dependent name lookup") in C++11:
[C++11: C.2.6]: 14.6.4.2
Change: Allow dependent calls of functions with internal linkage
Rationale: Overly constrained, simplify overload resolution rules.
resulting in:
[C++11: 14.6.4.2/1]: For a function call that depends on a template parameter, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2, 3.4.3) except that:
For the part of the lookup using unqualified name lookup (3.4.1) or qualified name lookup (3.4.3), only function declarations from the template definition context are found.
For the part of the lookup using associated namespaces (3.4.2), only function declarations found in either the template definition context or the template instantiation context are found.
[..]
(Spot the missing "with external linkage" qualification.)
Issue #561 ("Internal linkage functions in dependent name lookup"), the proposal that led to the restriction being removed in C++11, asks:
Furthermore, is it really necessary to exclude internal linkage functions from the lookup? Doesn't the ODR give implementations sufficient latitude to handle this case without another wrinkle on name lookup?
With the later answer:
The consensus of the group was that [..] internal-linkage functions should be found by the lookup (although they may result in errors if selected by overload resolution).
Question
What was the original practical rationale for the restriction?
It seems like there must have been one, since the original standard wording went out of its way to limit lookup to symbols with external linkage.
Is it just that "[internal-linkage functions] may result in errors if selected by overload resolution", and that through the 2000s opinion shifted over how important this was? Or did something else change, perhaps as an indirect consequence of new wording elsewhere for a different C++11 feature?
I would suspect it's related to the infamous export template feature of C++98. Think about it. Once you allow the possibility of template definitions appearing in separate translation units, but still not truly compilable until the template arguments are specified (i.e., the template is instantiated), you get into this twilight zone where the TU with the definition of the template and the TU with the instantiation have to obey linker-visibility rules (i.e., separation model) while sharing their contexts in terms of overload resolution. The solution to that problem is to allow only functions with external linkage in the dependent name lookups.
Here's an example. One of the lesser known "feature" of exported templates is that you could have, in the template's TU, some functions or classes with internal linkage (i.e., marked static or in an un-named namespace). What if the TU with the instantiation has a internal-linkage function too, one that would be ambiguous with or possibly superceded by the one in the template's TU? That's a bit of a surreal problem, I know, it's the bizarro world of exported templates. The only way to avoid very surprising behavior is to rule out all internal-linkage functions from the lookups. Consider also that no-one had a clear idea of how to actually implement exported templates, and it would probably seem even more impossible to implement without this restriction.
And so, once exported templates are out, the restriction on dependent name lookups seems clearly useless and it was taken out without much debate. At least, that makes perfect sense to me, but, of course, it's speculation.
Here's a concrete example:
// in exptemp.h
export template <typename T> bool is_valid(T value);
// in exptemp.cpp
namespace {
bool is_space(char c) {
return (c == ' ') || (c == '\t');
};
};
template <typename T>
bool is_valid(T value) {
return is_space(value);
};
// in test.cpp
#include "exptemp.h"
namespace {
bool is_space(char c) {
return (c == ' ') || (c == '\t') || (c == '\n');
};
};
int main() {
char c = '\n';
return is_valid(c); // will this return 0 or 1 ?!?!?
};
As far as I know, it's purely historical -- it seems to have originally been banned because cfront's name mangling wasn't sufficient to handle it correctly.
At one point, Anthony Williams wrote a paper proposing that it would be allowed, and telling how to do it -- but AFAIK, that paper has never been accepted nor its requirements edited into the standard. I suspect that's as much a matter of timing as anything else though. It was proposed in 2001, so what they were working on at the time (C++ 2003) wasn't intended to add much new material, and by the time they started working in earnest on C++11, it seems to have been mostly forgotten.