Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Non pre-declared function call works for class types but not primitive types

In the following code

template <typename T>
void foo(T) {
    bar(T{});
}

class Something {};
void bar(Something) {}

int main() {
    foo(Something{});
}

(https://wandbox.org/permlink/l2hxdZofLjZUoH4q)

When we call foo() with a Something parameter, everything works as expected, the call dispatches to the bar(Something) overload.

But when I change the argument to an integer and provide a bar(int) overload, I get an error

template <typename T>
void foo(T) {
    bar(T{});
}

void bar(int) {}

int main() {
    foo(int{});
}

Error:

error: call to function 'bar' that is neither visible in the template definition nor found by argument-dependent lookup

(https://wandbox.org/permlink/GI6wGlJYxGO4svEI)

In the class case, I have not defined bar() in a namespace along with the definition of Something. Meaning that I am not getting ADL. Then why does the code work with class types?

like image 524
Curious Avatar asked Aug 18 '18 05:08

Curious


1 Answers

Then why does the code work with class types?

According to §6.4.2/2.1:

The sets of namespaces and classes are determined in the following way:

  • If T is a fundamental type, its associated sets of namespaces and classes are both empty.

So upon writing foo(int), the compiler will have an empty set of namespaces and classes to be considered. The call to bar thus must fail, as it is not declared yet. If you declare foo(int) on beforehand, your code will compile:

void bar(int);

template <typename T>
void foo(T) {
    bar(T{});
}

void bar(int) {}

int main() {
    foo(int{});
}

On the other hand, in the case of the foo(Something), the (global) namespace will be part of the lookup, so the compiler actively scans the namespace for a function named bar that can be called with Something instances.

like image 112
Jodocus Avatar answered Sep 29 '22 04:09

Jodocus