Argument-dependent lookup and function templates [duplicate]
Asked Answered
C

2

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?

Connective answered 18/12, 2015 at 9:20 Comment(4)
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.Leola
I know it is a brittle way to omit using declaration. Just as a comparison to the second one >_<|||.Connective
@chihyang: Better example would be begin(str).Godspeed
@chihyang: That wasn't my point at all. What matters in your example is the type of the iterator.Leola
L
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
Leola answered 18/12, 2015 at 9:42 Comment(5)
DemoLeola
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!Connective
@chihyang: Yeah. But I hope in time you will find that this isn't usually such a big deal in real-world applications.Leola
@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.Leola
Yea. I always omitted using declarations for library algorithms. Maybe I should change this bad habit after understanding ADL. Thanks.Connective
G
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).

Godspeed answered 18/12, 2015 at 9:34 Comment(2)
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.Leola
@KerrekSB: Indeed. reworded.Godspeed

© 2022 - 2024 — McMap. All rights reserved.