Argument-dependent lookup of dependent names - c++

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).

Related

Template dependent name resolution should not find declarations with no linkage?

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.

C++ ODR-rule for default arguments of template functions

In the current draft of the C++ standard, there is the following paragraph ([temp] p.6]):
A template name has 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, 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. Template definitions shall obey the one-definition rule. [ Note: Default arguments for function templates and for member functions of class templates are considered definitions for the purpose of template instantiation ([temp.decls]) and must also obey the one-definition rule. — end note ]
I do not understand what the highlighted part means. How could I break the one definition rule using default arguments? Is there a way to "re-define" them?
The OP seems to be asking a few different questions:
What does the first part ("considered definitions for the purpose of template instantiation") mean?
What does the second part ("must also obey the one-definition rule") mean?
Isn't the part about the one-definition rule redundant with [basic.def.odr]/14.4 (which, at the time, was known as [basic.def.odr]/12.1)?
Assuming that the intent is e.g. to prohibit the same function template from having two different default arguments for the same parameter in different translation units such that the two default arguments don't have the same value, is this issue specific to templates? If not, then why does it need to be mentioned here at all?
Answer to question 1
That part of the note references [temp.decls], and [temp.decls.general]/3 elaborates:
For purposes of name lookup and instantiation, default arguments, type-constraints, requires-clauses (13.1), and noexcept-specifiers of function templates and of member functions of class templates are considered definitions; each default argument, type-constraint, requires-clause, or noexcept-specifier is a separate definition which is unrelated to the templated function definition or to any other default arguments, type-constraints, requires-clauses, or noexcept-specifiers. For the purpose of instantiation, the substatements of a constexpr if statement (8.5.2) are considered definitions.
Thus, it seems to be simply reminding the reader that default arguments are subject to instantiation separately from the function templates (or member functions of class templates) that they belong to.
Answer to question 2
The part about the one-definition rule appears to be reminding the reader that if the same default argument of a function template (or member function of class template) appears in multiple translation units, those multiple definitions must be "the same" in the sense of the one-definition rule ([basic.def.odr]/14). xskxzr already gave an example of how this could potentially be violated:
// TU 1
template <typename T> void foo(int = 0);
// TU 2
template <typename T> void foo(int = 1);
Answer to question 3
In the current standard, default arguments are a kind of "definable item" ([basic.def.odr]/1.6) so the rule that multiple definitions in different translation units must be identical applies to them just as it does to class definitions, inline function definitions, and so on ([basic.def.odr]/14). This does make the note redundant, which is fine. Notes are non-normative, so they ought to be redundant. Notes are often used to clarify normative text or to draw the reader's attention to a possibly surprising consequence of the normative text.
Answer to question 4
The first half, about instantiation, is obviously specific to templates. The second half is not now specific to templates, but it used to be. In C++20, it was made illegal for the same function parameter to be given different default arguments by different translation units; prior to C++17, it was legal. (This is [diff.cpp17.dcl.dcl]/2 in the "Compatibility" section of C++20.)
To be specific, from C++98 through C++17, therefore, it was permitted for non-template functions to have different default arguments in different translation units, but it was not permitted for function templates; therefore, the rule about default arguments being definitions that are subject to the one-definition rule was specific to function templates (and member functions of class templates). The wording of the note has not changed since C++98.
It might be more clear if the wording of the note were now changed to:
Default arguments for function templates and for member functions of class templates are considered definitions for the purpose of template instantiation ([temp.decls]) and, like default arguments of non-templated functions, must also obey the one-definition rule.
I don't think this change is necessary, though. The standard cannot be expected to be a particularly well-written document, as it is maintained by volunteers who already have their hands full with determining what the normative rules should be. You should expect that there will be times when you will look at something in the standard and wonder "why isn't this written in a different way?" And usually there will be some historical reason, but even if you can't figure out what that reason is, you shouldn't let it detract from your ability to understand what the standard is saying.

Can using a lambda in header files violate the ODR?

Can the following be written in a header file:
inline void f () { std::function<void ()> func = [] {}; }
or
class C { std::function<void ()> func = [] {}; C () {} };
I guess in each source file, the lambda's type may be different and therefore the contained type in std::function (target_type's results will differ).
Is this an ODR (One Definition Rule) violation, despite looking like a common pattern and a reasonable thing to do? Does the second sample violate the ODR every time or only if at least one constructor is in a header file?
This boils down to whether or not a lambda's type differs across translation units. If it does, it may affect template argument deduction and potentially cause different functions to be called - in what are meant to be consistent definitions. That would violate the ODR (see below).
However, that isn't intended. In fact, this problem has already been touched on a while ago by core issue 765, which specifically names inline functions with external linkage - such as f:
7.1.2 [dcl.fct.spec] paragraph 4 specifies that local static variables and string literals appearing in the body of an inline function with
external linkage must be the same entities in every translation unit
in the program. Nothing is said, however, about whether local types
are likewise required to be the same.
Although a conforming program could always have determined this by use
of typeid, recent changes to C++ (allowing local types as template
type arguments, lambda expression closure classes) make this question
more pressing.
Notes from the July, 2009 meeting:
The types are intended to be the same.
Now, the resolution incorporated the following wording into [dcl.fct.spec]/4:
A type defined within the body of an extern inline function is the same type in every translation unit.
(NB: MSVC isn't regarding the above wording yet, although it might in the next release).
Lambdas inside such functions' bodies are therefore safe, since the closure type's definition is indeed at block scope ([expr.prim.lambda]/3).
Hence multiple definitions of f were ever well-defined.
This resolution certainly doesn't cover all scenarios, as there are many more kinds of entities with external linkage that can make use of lambdas, function templates in particular - this should be covered by another core issue.
In the meantime, Itanium already contains appropriate rules to ensure that such lambdas' types coincide in more situations, hence Clang and GCC should already mostly behave as intended.
Standardese on why differing closure types are an ODR violation follows. Consider bullet points (6.2) and (6.4) in [basic.def.odr]/6:
There can be more than one definition of […]. Given such an entity named D defined in more than one translation unit, then each definition of D shall consist of the
same sequence of tokens; and
(6.2) - in each definition of D, corresponding names, looked up
according to [basic.lookup], shall refer to an entity defined within
the definition of D, or shall refer to the same entity, after
overload resolution ([over.match]) and after matching of partial
template specialization ([temp.over]), […]; and
(6.4) - in each definition of D, the overloaded operators referred to,
the implicit calls to conversion functions, constructors,
operator new functions and operator delete functions, shall refer to
the same function, or to a function defined within the definition of
D; […]
What this effectively means is that any functions called in the entity's definition shall be the same in all translation units - or have been defined inside its definition, like local classes and their members. I.e. usage of a lambda per se is not problematic, but passing it to function templates clearly is, since these are defined outside the definition.
In your example with C, the closure type is defined within the class (whose scope is the smallest enclosing one). If the closure type differs in two TUs, which the standard may unintentionally imply with the uniqueness of a closure type, the constructor instantiates and calls different specializations of function's constructor template, violating (6.4) in the above quote.
UPDATED
After all I agree with #Columbo answer, but want to add the practical five cents :)
Although the ODR violation sounds dangerous, it's not really a serious problem in this particular case. The lambda classes created in different TUs are equivalent except their typeids. So unless you have to cope with the typeid of a header-defined lambda (or a type depending on the lambda), you are safe.
Now, when the ODR violation is reported as a bug, there is a big chance that it will be fixed in compilers that have the problem e.g. MSVC and probably some other ones which don't follow the Itanium ABI. Note that Itanium ABI conformant compilers (e.g. gcc and clang) are already producing ODR-correct code for header-defined lambdas.

Why did C++03 require template parameters to have external linkage?

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.

Why can't templates take function local types?

In C++ it's OK to have a funcction that takes a function local type:
int main() {
struct S { static void M(const S& s) { } };
S s;
S::M(s);
}
but not OK to have a template that does:
template<typename T> void Foo(const T& t) { }
int main() {
struct S { } s;
Foo(s); // Line 5: error: no matching function for call to 'Foo(main()::S&)'
}
14.3.1 paragraph 2 in the c++ standard.
A type with no linkage [...] shall not be used as a template-argument for a template type-parameter
Why does C++ disallow that?
The best explanation I've heard so far it that inner types have no linkage and that this could imply that a function that takes them as an arg must have no linkage. But there is no reason I can see that a template instantiation must have linkage.
p.s. Please don't just say "thats not allowed because the standard says it's not"
I believe the difficulty that was foreseen was with two instantiations of Foo<T> actually meaning entirely different things, because T wasn't the same for both. Quite a few early implementations of templates (including cfront's) used a repository of template instantiations, so the compiler could automatically instantiate a template over a required type when/if it was found that an instantiation over that type wasn't already in the repository.
To make that work with local types, the repository wouldn't just be able to store the type over which the template was instantiated, but instead it would have to do something like creating a complete "path" to the type for the instantiation. While that's probably possible, I think it was seen as a lot of extra work for little (if any) real benefit.
Since then, the rules have changed enough that the compiler is already required to do something that's just about equivalent, finding (and coalescing) instantiations over the same type at different places (including across TUs) so that two instantiations of foo<int> (for example) don't violate the ODR. Based on that realization, the restriction has been loosened in (the current draft of) C++0x (you still can't instantiate a template class over a local type, but you can use a local type as parameter to a template function).
I'm guessing it is because it would require the template to be effectively instantiated within the scope of the function, since that is where such types are visible. However, at the same time, template instantiations are supposed to act as if they are in the scope in which the template is defined. I'm sure this it's possible to deal with that somehow, but if I'm right the standards body decided not to put that burden on compiler writers.
A similar decision was the reason vector<vector<int>> is invalid syntax per the standard; detecting that construction requires some interaction between compiler lexer and parser phases. However, that's changing, because the C++0x standards folk found that all the compilers are detecting it anyway to emit sane error messages.
I suspect that if it were to be demonstrated that allowing this construction was trivial to implement, and that it didn't introduce any ambiguities in the language scoping rules, you might someday see the standard changed here too.