4

Why argument dependent lookup doesn't consider Foo::dynamicCast, shouldn't it consider namespace Foo because the Base class is in this namespace?

#include <memory>
using namespace std;

namespace Foo
{

template<typename P, typename T> P*
dynamicCast(T* t)
{
    return dynamic_cast<P*>(t);
}

class Base
{
public:
    virtual ~Base() = default;
};

}

namespace Test
{

class Derived : public Foo::Base
{
};

}

shared_ptr<Foo::Base> b = make_shared<Test::Derived>();
auto d = dynamicCast<Test::Derived>(b.get());
Jarod42
  • 203,559
  • 14
  • 181
  • 302
José
  • 3,041
  • 8
  • 37
  • 58
  • tested a little. This works: http://ideone.com/tX3JcU – bolov Nov 25 '15 at 16:57
  • ADL isn't triggered when using explicit template arguments. – David G Nov 25 '15 at 16:57
  • 2
    @0x499602D2: A little more complicated: except if there is a visible function template of the same name: [Demo](http://coliru.stacked-crooked.com/a/15b614250f6ad61c). – Jarod42 Nov 25 '15 at 17:53

2 Answers2

4

In order to even understand that you have a function call with a template, and not a bunch of < and > operators, the compiler must know you have a function template; and in order to understand that, it must know what namespace to look it up in. And in order to know that, it must understand the namespaces of the function arguments. And in order to understand that it must know there are function arguments around. Which, as we have seen, depends on knowing that there's a function call to begin with. Which the compiler doesn't know until it finds a template declaration. See the problem?

Because of that, ADL is only ever considered if the postfix-expression in the function call is an unqualified-id. Which dynamicCast<Test::Derived> is not <edit> only if dynamicCast is known to be a template-name, which is determined during normal unqualified lookup, which doesn't look into the namespace where the template is declared.

As @T.C. observed, one can declare an unrelated function template named dynamicCast in the global namespace in order to make ADL work.

</edit>

In a better world we would have an option to write template foo<whatever> in any context and disambiguate the angle brackets. Maybe in C++20.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • `dynamicCast` **is** an *unqualified-id*, **if** `dynamicCast` is a *template-name*. A `template void dynamicCast() = delete;` that is picked up by normal unqualified lookup is sufficient to make ADL work. – T.C. Nov 25 '15 at 19:00
  • @T.C. you're right of course, my std::fu is slow today. – n. m. could be an AI Nov 25 '15 at 19:56
3

Template functions with explicit template arguments are not found via ADL. Maybe a parsing problem, do not know why.

Another example is std::get. You cannot get<3>(some_tuple) without a using statement.

You can work around this by passing the arguments you would pass as template args as tag types. You can also do a one-two step external function plus internal ADL tag dispatched lookup (so the public function has to be qualified, but customization points of the internal tag-based ADL can be done).

// tag utilities:
template<class T>struct tag_t{using type=T;constexpr tag_t(){};};
template<class T>constexpr tag_t<T> tag={};

namespace some{
  template<class T, class U>
  T* dynamic(tag_t<T>, U* u){
    return dynamic_cast<T>(u);
  }
  struct bob{};
}

Now dynamic(tag<int>,new some::bob{}) will find dynamic via ADL.

I do not have chapter and verse from the standard for you.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524