Home > Back-end >  Code not compiling when template functions are placed in a certain order
Code not compiling when template functions are placed in a certain order

Time:08-11

The following program compiles successfully.

template<typename T>
T sum(T x) {
    return x;
}

template<typename T, typename... Args>
T sum(T x, Args... args) {
    return x   sum(args...);
    
}

int main() {
    sum(1, 2, 3, 4, 5);

}

However, when I switch the order in which the template functions are written, it no longer compiles:

template<typename T, typename... Args>
T sum(T x, Args... args) {
    return x   sum(args...);

}

template<typename T>
T sum(T x) {
    return x;
}

int main() {
    sum(1, 2, 3, 4, 5);

}

Why does this happen? Aren't both functions already defined prior to being called in main()? Why does the order in which they're written in matter?

CodePudding user response:

At the heart of your question is the following issue: when a function name, such as sum, appears inside a function template, what function does it refer to?

You wrote:

Aren't both functions already defined prior to being called in main()? Why does the order in which they're written in matter?

You seem to have the following expectation: that when a function template is instantiated, and a function name such as sum appears inside it, the compiler finds all overloads of sum that have been declared so far. Thus, according to your theory, since the sum function template is not instantiated until it is called in main, at that point, both overloads of sum are visible, so the recursive calls to sum should consider both overloads and eventually select the unary one to terminate the recursion.

However, as you've seen, that's not the case. If the variadic sum is declared first, it eventually recursively calls itself with a single argument (ignoring the unary sum overload declared later), which then attempts to call sum() (no arguments), leading to a compilation error.

In this example, it thus appears that when the compiler sees a call to sum inside a function template, it only finds functions named sum that have been declared at the point of the call. When you switched the order around, you made it so that the variadic sum could never call the unary sum.

Actually though, the truth is more complicated. The C standard requires a behaviour that is colloquially referred to as "two-phase lookup". What this means is:

  1. when the compiler sees the definition of the function template, it finds all functions named sum that have been declared so far, and
  2. when the compiler later instantiates the function template, it uses argument-dependent lookup to find additional overloads of sum regardless of whether they were declared before or after the enclosing template.

In your code, sum is only ever called with arguments of type int, which does not belong to any namespace. Thus, the variadic sum only finds itself in phase 1, and nothing in phase 2.

  • Related