An answer to this question says in the following code:
#include <vector>
using std::vector;
struct foo {
template<typename U>
void vector();
};
int main() {
foo f;
f.vector<int>(); // ambiguous!
}
The last line in main is ambiguous, because the compiler not only looks up vector
within foo
, but also as an unqualified name starting from within main
. So it finds both std::vector
and foo::vector
. To fix this, you have to write
f.foo::vector<int>();
I've tried this program on all popular C++ compilers ( g++
, clang++
, vc++
and Intel C++ ) and all compilers compile this program without any error. So, why did he say that there is ambiguity in this program ? What does the C++ standard say about this ?
This was the case in C++03 but this was fixed in C++11. We can even try this live in godbolt with clang using -std=c++03 flag. We do receive a warning:
<source>:11:5: warning: lookup of 'vector' in member access expression is ambiguous; using member of 'foo' [-Wambiguous-member-template]
f.vector<int>(); // ambiguous!
^
Older clang documentation using the same example from the defect report below when describing the warning for -Wambiguous-member-template
.
This was changed via defect report 1111: Remove dual-scope lookup of member template names which explains the issue:
According to 6.4.5 [basic.lookup.classref] paragraph 1,
In a class member access expression (8.2.5 [expr.ref]), if the . or -> token is immediately followed by an identifier followed by a <, the identifier must be looked up to determine whether the < is the beginning of a template argument list (17.2 [temp.names]) or a less-than operator. The identifier is first looked up in the class of the object expression. If the identifier is not found, it is then looked up in the context of the entire postfix-expression and shall name a class template. If the lookup in the class of the object expression finds a template, the name is also looked up in the context of the entire postfix-expression and
if the name is not found, the name found in the class of the object expression is used, otherwise
if the name is found in the context of the entire postfix-expression and does not name a class template, the name found in the class of the object expression is used, otherwise
if the name found is a class template, it shall refer to the same entity as the one found in the class of the object expression, otherwise the program is ill-formed.
This makes the following ill-formed:
#include <set> using std::set; struct X { template <typename T> void set(const T& value); }; void foo() { X x; x.set<double>(3.2); }
That's confusing and unnecessary. The compiler has already done the lookup in X's scope, and the obviously-correct resolution is that one, not the identifier from the postfix-expression's scope. Issue 305 fixed a similar issue for destructor names but missed member functions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With