Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does using the scope resolution operator change which overloaded template in the global namespace gets called?

Consider the following code:

#include <iostream>

template <class W, class T>
void foo(W& a, T& t)
{
  std::cout << "generic" << std::endl;
}

template <template <bool> class W, class T>
void foo(W<true>& a, const T& t)
{
  foo(a, const_cast<T&>(t));
}

template <class W>
void foo(W& a, int& t)
{
  std::cout << "int" << std::endl;
}

template <bool> struct what;
template<> struct what<true> { };

int main() {
  const int ci = 10;
  what<true> wt;

  foo(wt, ci);

  return 0;
}

The output is (ideone link):

int

This makes sense to me: foo(what<true>&, const int&) matches the const_cast overload, which then calls foo(what<true>&, int&), which matches the int overload.

Yet if I change the const_cast function to the following:

template <template <bool> class W, class T>
void foo(W<true>& a, const T& t)
{
    ::foo(a, const_cast<T&>(t));
}

The output is now (ideone link):

generic

This doesn't make sense to me. Why does changing that const_cast overload of foo to call ::foo cause the generic version to get called instead of the int version?

My understanding of :: is that it was just to disambiguate which function to call in the case you have a method or a function in the global namespace. The const_cast overload still matches, which should then call ::foo(what<true>&, int&), which should match the int specialization - shouldn't it?

Further, if I change the order and place the const_cast overload using ::foo after the int specialization, then the int specialization gets called (ideone link). Why does the order of definition matter here?

like image 806
Claudiu Avatar asked May 06 '15 16:05

Claudiu


1 Answers

Names declared after the template can only be found via argument-dependent name lookup. Your overload of foo for int& is only found because one of the types involved, W<true>, is a specialization of a class template declared in the global namespace. Hence ADL looks for declarations in the global namespace in the instantiation context and finds the (more specialized), desired overload.

::foo is a qualified-id, which suppresses ADL, hence only names declared in the definition context are considered.

like image 97
Columbo Avatar answered Sep 28 '22 22:09

Columbo