Should this function call be ambiguous? - c++

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.

Related

where's the relevant rule for phase two name lookup of template instantiation in the current standard

template<typename T>
void fun(T t){
foo(t); //#1 foo is a dependent name
}
void foo(int){
}
int main(){
fun(0); // #2 ill-formed
}
Since the unqualified-id foo is a dependent name as per temp.dep#2, So, the lookup name rule for this name should obey the following rule, which is mentioned in the note of [temp.dep#2]
[ Note: Such names are unbound and are looked up at the point of the template instantiation ([temp.point]) in both the context of the template definition and the context of the point of instantiation ([temp.dep.candidate]). — end note ]
The lookup rule for a dependent name is clearly written in c++17 standard, that is:
temp.dep.res#1
In resolving dependent names, names from the following sources are considered:
Declarations that are visible at the point of definition of the template.
Declarations from namespaces associated with the types of the function arguments both from the instantiation context ([temp.point]) and from the definition context.
And 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, 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 found in either the template definition context or the template instantiation context are found.
In other words, these rules mean that only ADL is used to perform in phase two lookup.
However, I cannot find the relevant rule in the current standard(i.e, c++20). [temp.dep.res#1] has been removed from the current standard. [temp.dep.candidate#1] has been modified as:
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 from the template definition context ([basic.lookup.unqual], [basic.lookup.argdep]). [ Note: For the part of the lookup using associated namespaces ([basic.lookup.argdep]), function declarations found in the template instantiation context are found by this lookup, as described in [basic.lookup.argdep]. — end note ] If the call would be ill-formed or would find a better match had the lookup within the associated namespaces considered all the function declarations with external linkage introduced in those namespaces in all translation units, not just considering those declarations found in the template definition and template instantiation contexts, then the program has undefined behavior.
It's just to be a note in the current standard. It appears to me that the current standard does not clearly describe how the lookup rule performs for an unqualified dependent name in a function call. In the current standard, where's the relevant rule states that only ADL will perform in the second phase? It's unclear. If the usual unqualified look rule will be performed in the second phase, #2 would be well-formed due to void foo(int) can be found in the instantiation context by unqualified lookup. If I miss anything, where's the relevant rule?
In other words, these rules mean that only ADL is used to perform in phase two lookup.
This is the wrong conclusion to draw from the given specification quotes. You seem to be confusing two different concepts.
The first concept is what is commonly called "two-phase lookup": the fact that when a template gets parsed, names which are dependent on template parameters cannot be looked up at parse time. They can only be lookup up at instantiation time. There are two phases of lookup: one for non-dependent names, and one for dependent names.
The second concept is just name lookup, which has two scopes of names to search: regular unqualified lookup (defined in [basic.lookup.unqual]) and argument-dependent lookup (defined in [basic.lookup.argdep]). Unqualified lookup searches in the scope of the code itself, while ADL searches in the scope of the namespace of a function's arguments.
Both phases of template name lookup use both of these scopes. To be clear, dependent name lookup also does unqualified lookup. This is why one of the bullet points you quoted said "for the part of the lookup using unqualified name lookup... ". If dependent name lookup didn't use the rules for unqualified name lookup, it wouldn't have mentioned them.
Now, dependent name lookup does restrict what the candidate names are compared to the regular rules. But it doesn't restrict it to just ADL; it does both scopes of lookup.
These restrictions used to be specified in [temp.dep.candidate]/1, as you pointed out. But they got moved around a bit.
For the unqualified lookup part, the new [temp.dep.candidate]/1 covers that as you quoted it, because it says "usual lookup rules from the template definition context". This specifies the context of the unqualified lookup as being the template's definition only.
Note that the second bullet point also says to look in that scope, so it covers part of that.
The rest of the second bullet point is covered by [basic.lookup.argdep]/4.5:
If the lookup is for a dependent name ([temp.dep], [temp.dep.candidate]), any declaration D in N is visible if D would be visible to qualified name lookup ([namespace.qual]) at any point in the instantiation context ([module.context]) of the lookup, unless D is declared in another translation unit, attached to the global module, and is either discarded ([module.global.frag]) or has internal linkage.
This expands the lookup to include the "instantiation context", which largely matches the C++17 text (though with module-based modifications).

Name lookup in template base: why do we add this->

Consider the following:
struct Base {
void foo();
};
template <class T>
struct Derived : Base {
void bar() {
this->foo();
}
};
Typically, we explain that this-> makes foo() a dependent name, so its lookup is posponed to the second phase, i.e. to the template instantiation point.
But the second phase lookup invokes only ADL, which does not consider member functions, does it?
I'd appreciate any pointer to the Standard paragraph that explains why the above code compiles.
But the second phase lookup invokes only ADL, which does not consider member functions, does it?
It does not. However ADL adds to the lookup set, it does not comprise all of it. Also, the idea you are paraphrasing here applies to a postfix-expression in postfix-expression(args), when said postfix-expression is an unqualified-id.
[temp.dep]
1 ... In an expression of the form:
postfix-expression ( expression-listopt )
where the postfix-expression is an unqualified-id, the unqualified-id
denotes a dependent name if
[... specific conditions ...]
If an operand of an operator is a type-dependent expression, the
operator also denotes a dependent name. Such names are unbound and are
looked up at the point of the template instantiation ([temp.point]) in
both the context of the template definition and the context of the
point of instantiation.
So if you had there foo() instead, lookup would not consider members, and would instead try only free functions, both at the point of definition and instantiation (where ADL can add to the lookup set, assuming we had a dependent expression).
But for this->foo (I omitted the call intentionally, to discuss the postfix-expression), we have class member access. And here other paragraphs apply:
[temp.dep.type]
5 A name is a member of the current instantiation if it is
[...]
An id-expression denoting the member in a class member access expression for which the type of the object expression is the current instantiation, and the id-expression, when looked up, refers to at least one member of a class that is the current instantiation or a non-dependent base class thereof. [ Note: If no such member is found, and the current instantiation has any dependent base classes, then the id-expression is a member of an unknown specialization; see below.  — end note ]
6 A name is a member of an unknown specialization if it is
[...]
An id-expression denoting the member in a class member access expression in which either
the type of the object expression is the current instantiation, the current instantiation has at least one dependent base class, and name
lookup of the id-expression does not find a member of a class that is
the current instantiation or a non-dependent base class thereof; or
7 Similarly, if the id-expression in a class member access expression for which the type of the object expression is the current instantiation does not refer to a member of the current instantiation or a member of an unknown specialization, the program is ill-formed even if the template containing the member access expression is not instantiated; no diagnostic required.
These bullets tell us what lookup to perform when this->foo is encountered. It looks up members only. In our case, we have a non-dependent base class in the current instantiation, so that's where the member is to be found, unambiguously.
Having found the member function, the postfix-expression this->foo denotes a callable, and that is how the function call is resolved.
The phrase “two-phase lookup” is widely misunderstood, even among experts. C++17 said both
Such names are unbound and are looked up at the point of the template instantiation (17.6.4.1) in both the context of the template definition and the context of the point of instantiation.
(in [temp.dep]/1) and
In resolving dependent names, names from the following sources are considered:
— Declarations that are visible at the point of definition of the template.
— Declarations from namespaces associated with the types of the function arguments both from the
instantiation context (17.6.4.1) and from the definition context.
(in [temp.dep.res]/1), each of which seems to suggest that these are the two phases. However, a better way of interpreting this (unofficial) phrase is that lookup is done
from the template definition: for non-dependent names
during instantiation: from the definition but also, via ADL only, from the instantiation context
The former can be done when parsing the template definition, but no diagnostic is required for uninstantiable templates ([temp.res]/8). Note that the latter includes more than ADL.
The relevant wording has been clarified recently; it now merely says
[Note: For the part of the lookup using associated namespaces ([basic.lookup.argdep]), function declarations found in the template instantiation context are found by this lookup, as described in [basic.lookup.argdep]. — end note]
as a reminder of the difference in the second phase. Nonetheless, it confusingly uses dependent name only to refer to unqualified dependent names/operators ([temp.dep]/2). Names like Derived::foo (from the this->) are clearly dependent; as qualified names, they’re not subject to ADL, but they are still looked up during instantiation—which allows results from a dependent base to be found. (Your example has a non-dependent base, but that’s available then too.)

Why do type traits not work with types in namespace scope?

I'm designing a type register feature for my C++ serializing library.
But I encountered a strange problem about type traits.
I'm using Visual Studio 2017 with /std:c++latest.
#include <type_traits>
int reg(...);
template<class T>
constexpr bool is_known = !std::is_same_v<decltype(reg((T*)1)), int>;
//----- for type1 in global scope ------
struct type1 {};
void reg(type1 *);
static_assert(is_known<type1>); // success
//----- for type2 in namespace scope ----
namespace ns { struct type2 { }; }
void reg(ns::type2 *);
static_assert(is_known<ns::type2>); // fail!!!!
Static assert succeeds for type1, which is in global scope, but fails for namespace scope type2.
Why is there a difference?
There are two sets of places examined when the lookup of reg((T*)) is done to find which reg is being referred to. The first is where the template is declared (where int reg(...) is visible), the second is ADL at the point where the template is first instantiated with a new type.
ADL (argument dependent lookup) on ns::type2* does not examine the global namespace. It examines namespaces associated with that type, namely ns in this case. ADL does not examine namespaces "surrounding" or "above" associated namespaces.
ADL for ::type1 does examine the global namespace.
Templates are not macros. They don't act as if you copy-pasted the generated code at the point you instantiated it. MSVC used to treat templates more like macros, but they have increasingly come into compliance with the standard. The name they gave to their compliance efforts is "two phase name lookup" if you want to track why it broke in a specific version.
The fix is to move reg into the namespace of ns::type2, or otherwise ensure that the namespace you define reg in is associated with the argument to reg (like use tag templates instead of pointers), or define reg before you define its use in decltype. Or something fancier; without underlying problem description I cannot guess.
TLDR The mechanism is known as the 2 phase lookup, and its rules are arcane. Rule of thumb is to always declare functions in the same namespace as the type it uses to avoid shenanigans.
2 phase lookup occurs when there is a dependent name, at which point the name lookup is deferred to the point of instantiation. If the name is unqualified, the result of the lookup is the union of unqualified lookup at the point of definition and argument dependent lookup at the point of instantiation.
Now what the hell does that even mean?
Dependent name
A name (eg a function name) is dependent if its meaning depends on a template parameter. In your case, reg depends on T because the argument type T* depends on T.
Point of instantiation
Template aliases aren't types, they represent an entire family of types. The type is said to be instantiated from the template when you give it a parameter. The point of instantiation is the place in the program where the template alias is first used with an actual parameter.
Unqualified name
A name is said to be unqualified if there is no scope resolution operator before it, eg reg is unqualified.
Unqualified lookup
Whenever a name appears in the program, its declaration has to be found, this is called name lookup. Unqualified lookup looks up the name from the scope where the name appears and searches outwards sequentially.
Argument dependent lookup
Also known as ADL, which is another lookup rule, it applies when the function name being looked up is unqualified and one of a function's arguments is a user defined type. It finds the name in the associated namespaces of the type. The associated namespaces includes the namespace where the type is defined, among many others.
In conclusion, since is_known is defined before the following overloads of reg, unqualified lookup may only find reg(...). Since reg(ns::type2*) isn't within the associated namespace of ns::type2, it isn't found by ADL either.

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.

function lookup and namespaces

If a function cannot be found in the scope where it is called, looking up in the namespaces of its arguments will follow. I have a few questions.
If there are several arguments in different namespaces, which namespace will be first looked up? Is it the namespace of the first argument?
f(A::T t, B:U u); // Is namespace A looked up first?
More complex for template classes, like
f(A::T<B::U> t); // Namespace A or B is looked up first?
Actually, there is no order among the namespaces for ADL. All relevant namespaces are searched, and all functions thus found form the set of candidates for overload resolution.
Also note that unlike what you say in the question, ADL is performed even when a function is found by unqualified lookup in the calling scope. The union of unqualified lookup and ADL is then used to find the best overload.
ADL is only suppressed if unqualified lookup at calling scope finds a class member, a non-function, or a block-scope non-using declaration.
The relevant rules are in C++14 3.4.2 [basic.lookup.argdep]. Quoting N4140, bold emphasis mine:
3 Let X be the lookup set produced by unqualified lookup (3.4.1) 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 or 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.