6

Here is an example:

#include <string>
#include <algorithm>
#include <memory>

using std::string;

int main()
{
    string str = "This is a string";

    // ok: needn't using declaration, ADL works
    auto it = find(str.begin(), str.end(), 'i');

    // error: why ADL doesn't work?
    std::shared_ptr<string> sp = make_shared<string>(str);
}

When I tried to compile this program, the compiler complained:

error: no template named 'make_shared'; did you mean 'std::make_shared'?
        std::shared_ptr<string> sp = make_shared<string>(str); // error...
                                     ^~~~~~~~~~~
                                     std::make_shared

I guess the first function find doesn't need using declaration because of argument-dependent lookup(ADL): the compiler would search the namespace where string resides(i.e. std) for the definition of find. But for the second function make_shared, it seems that ADL doesn't work: I have to use std::make_shared or using declaration instead. I know the definitions of two function templates are different: the former takes one of its template paramters(typename T or something like that) as function parameter type and returns the same type. The latter takes function parameter pack as function paramter and its return type is another template parameter. Is this difference that disables ADL? Or could you help answer the question and offer some references?

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
chihyang
  • 187
  • 6
  • 1
    The first usage is brittle. You're relying on the unspecified circumstance that the iterator type lives in `std`. If on another day the iterator type is `const char *`, it won't compile. – Kerrek SB Dec 18 '15 at 09:28
  • I know it is a brittle way to omit `using` declaration. Just as a comparison to the second one >_<|||. – chihyang Dec 18 '15 at 09:34
  • @chihyang: Better example would be `begin(str)`. – Jarod42 Dec 18 '15 at 09:37
  • 1
    @chihyang: That wasn't my point at all. What matters in your example is the type of the *iterator*. – Kerrek SB Dec 18 '15 at 09:39

2 Answers2

1

Argument-dependent lookup works for unqualified function call expressions. This is true for "normal" functions just as well as for function template specializations.

However, when you provide explicit template parameter for a template function, then the expression does not syntactically look like an function call:

foo<3>(x)  //   "foo less than three?"

That's why those cases don't trigger ADL. However, once a name is known to be a template, ADL does apply!

template <int> void foo();

foo<double, 5, T>(x);   // uses ADL
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • [Demo](https://ideone.com/SKc0Sh) – Kerrek SB Dec 18 '15 at 09:44
  • Well... I tried the way in your answer and it did work fine! But it really feels weird: declare another function template that we'll never use just to notify the compiler the name we are using is a template! Why is ADL so weird? On C++ Primer it takes less than 3 pages. But now it seem as if a huge pitfall! – chihyang Dec 18 '15 at 09:59
  • @chihyang: Yeah. But I hope in time you will find that this isn't usually such a big deal in real-world applications. – Kerrek SB Dec 18 '15 at 10:44
  • @chihyang; The main use for ADL is in creating customization points. You shouldn't use it for "direct" code like in your example. So the times you get exposed to this weirdness should be relatively few. – Kerrek SB Dec 18 '15 at 11:15
  • Yea. I always omitted `using` declarations for library algorithms. Maybe I should change this bad habit after understanding ADL. Thanks. – chihyang Dec 18 '15 at 11:43
0

Template methods don't use ADL when we specify explicitly its template argument with <> except if there is a visible template method in the scope (with same name).

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • Not quite.First off, this only applies to function calls with explicitly specified template parameters. Second, if you also have another function template in scope, ADL does apply. The restriction is essentially syntactic rather than profound: Without an existing declaration, the call expression doesn't syntactically look like a function call. – Kerrek SB Dec 18 '15 at 09:37
  • @KerrekSB: Indeed. reworded. – Jarod42 Dec 18 '15 at 09:41