2

How can I workaround this clang warning? This appears quite frequently with code that includes STL <set> and additionally has a templatized set() function.

I don't want to disable the warning globally, but also not manually for every file where <set> is included (too many).

template<typename T> struct set{};
template<typename T> struct trait { typedef const T& type; };
struct Value {
  template<typename T> void set(typename trait<T>::type value) {}
};
void foo() {
  Value v;
  v.set<double>(3.2);
}
clang.cpp:8:9: warning: lookup of 'set' in member access expression is ambiguous; using member of 'Value' [-Wambiguous-member-template]
      v.set(3.2);
        ^
clang.cpp:4:29: note: lookup in the object type 'Value' refers here
  template void set(typename trait::type value) {}
                ^
clang.cpp:1:29: note: lookup from the current scope refers here
template struct set{};
                ^
1 warning generated.

The obvious solution would be to not use templatized set() methods but that seems rather limiting.

  • 2
    What about a proper use of namespaces and avoiding using namesspace std? –  Dec 02 '13 at 11:22
  • Which version of clang are you using? – dyp Dec 02 '13 at 11:52
  • @DyP: release_34 from SVN – Martin Richtarsky Dec 02 '13 at 12:22
  • @MartinRichtarsky I think the whole issue has been resolved in [DR 1111](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1111), which has FDIS status - AFAIK it's part of the Standard now. So you should interpret the warning as *ill-formed in C++03, allowed and unambiguous now*. Understanding that, you might want to disable the warning as suggested by n.m. – dyp Dec 02 '13 at 21:53

2 Answers2

3

The warning appears to be invalid. The standard [basic.lookup.classref] doesn't seem to indicate there's an ambiguity, or require any diagnostic, in such cases. Here's the relevant passage:

  1. In a class member access expression (5.2.5), 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 (14.2) 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.

I would disable the warning globally.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • 2
    There seems to have been a change between n3242 and n3337, between which the Standard has been published. n3242 requires an error in this case, but more recent versions do not. n3242 [basic.lookup.classref]/1, bullet 3: "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." – dyp Dec 02 '13 at 11:50
  • @dyp this is a C++03 rule which was fixed in C++1 [see my answer here for more details](https://stackoverflow.com/a/52638779/1708801) and yes it is pretty wacky. – Shafik Yaghmour Oct 04 '18 at 16:08
2

You're right, the obvious solution is not to define conflicting template set methods and classes. The name lookup rules in your scope must not be ambiguous between the class and the method, i.e. the symbol set must not refer to both, you must use namespaces to disambiguate.

You probably don't define the set method in namespace std, so I can only assume you injected std::set in your scope, with using std::set or using namespace std.

Generally, using namepsace std if a bad idea, because you don't control the symbols it injects in your scope (depends on recursive includes), and you don't always control with what other symbols this may conflict.

In your case, as Dieter said, the simplest solution is to stop set from referring to std::set by removing relevant using clauses. You'd then have to use std::set to name it, instead of just set but there no longer would be any conflict.

Antoine
  • 13,494
  • 6
  • 40
  • 52