No best match found in ADL after creation. Is it UB?

Consider the following code, in which the location of the overloads f

causes some non-intuitive behavior. The code compiles without warnings in Clang 3.4.1 and gcc 4.8.

template<typename T>
struct A
{
    static const int value = sizeof(f(T()));
};

struct B
{
};

struct D : B
{
};

char f(B);

// instantiates A<D>, unqualified name lookup finds f(B) via ADL
static_assert(A<D>::value == sizeof(f(B())), ""); // passes

long f(D); // but wait, f(D) would be a better match!

// A<D> is already instantiated, f(D) is not found
static_assert(A<D>::value == sizeof(f(B())), ""); // passes

      

The C ++ 11 standard assumes that the above code causes undefined behavior:

[temp.dep.candidate]

For a function call that depends on a template parameter, candidate functions are found using the normal search rule, except that:

  • For the part of the search that uses unqualified name lookup or qualified name lookup, only function declarations were found from the context of the template definition.
  • For the search portion using related namespaces, only function declarations found in the template definition context or template instance context are found.

If the function name is an unqualified identifier and the call is poorly formed or finds a better match, search the related namespaces considered in all externally linked function declarations entered into those namespaces in all translation units, not just those declarations that were found in the template and in the context of the template instance, then the program has undefined behavior.

Does this code cause this particular style to be undefined? Can a high quality implementation be expected to result in a warning?

+3


source to share


1 answer


Is the above code causing this particular undefined behavior?

Yes. [Temp.point] / 7:

An expression creation context that depends on the template arguments a set of externally linked declarations declared before the template was created specialization in the same translation unit .

The point of instantiation is right after the first static_assert

-declaration:



For [...] specialization for [...] a static data member of a class, a template if the specialization is implicitly created because it is referenced from another specialized specialization [...]. Otherwise, the point of instantiation for such a specialization immediately follows the declaration or definition of the scope of the namespace belongs to the specialization.

So there really would be a better match if we looked at the second function declaration, which we couldn't, since it was declared after the moment of creation A<D>::value

. According to the rule you quoted, the code invokes undefined behavior.
This rule basically extends the ODR to dependent lookup of names in patterns.

Can a high quality implementation be expected to result in a warning?

I would not. Also consider undefined behavior to fall back to compile time; The compiler is allowed, but it is not required to issue a warning or error message if the code calls UB. Don't expect compilers to always point to illegal code.

+2


source







All Articles