Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template function overloading with identical signatures, why does this work?

Minimal program:

#include <stdio.h>

#include <type_traits>

template<typename S, typename T>
int foo(typename T::type s) {
    return 1;
}

template<typename S, typename T>
int foo(S s) {
    return 2;
}

int main(int argc, char* argv[]) {
    int x = 3;
    printf("%d\n", foo<int, std::enable_if<true, int>>(x));

    return 0;
}

output:

    1 

Why doesn't this give a compile error? When the template code is generated, wouldn't the functions int foo(typename T::type search) and int foo(S& search) have the same signature?

If you change the template function signatures a little bit, it still works (as I would expect given the example above):

template<typename S, typename T>
void foo(typename T::type s) {
    printf("a\n");
}

template<typename S, typename T>
void foo(S s) {
    printf("b\n");
}

Yet this doesn't and yet the only difference is that one has an int signature and the other is defined by the first template parameter.

template<typename S, typename T>
void foo(typename T::type s) {
    printf("a\n");
}

template<typename S, typename T>
void foo(int s) {
    printf("b\n");
}

Compiler error (Clang):

test.cpp:26:2: error: call to 'foo' is ambiguous
foo<std::enable_if<true, int>>(3);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:16:6: note: candidate function [with T = std::__1::enable_if<true, int>]
void foo(typename T::type s) {
        ^
test.cpp:21:6: note: candidate function [with T = std::__1::enable_if<true, int>]
void foo(int s) {
        ^
1 error generated.

I'm using code similar to this for a project I'm working on and I'm afraid that there's a subtly to the language that I'm not understanding that will cause some undefined behavior in certain cases. I should also mention that it does compile on both Clang and in VS11 so I don't think it's just a compiler bug.


Edit: Corrected second case (typo); added error message from Clang.

Edit #2: For those of you that asked what T::type means.

From http://en.cppreference.com/w/cpp/types/enable_if:

template< bool B, class T = void > struct enable_if;

If B is true, std::enable_if has a public member typedef type, equal to T; otherwise, there is no member typedef.

enable_if is a struct. Basically, if the expression evaluated in the first template parameter of enable_if is true (and in the case of my examples above, it is), then then there will be a public member type that has the same type as the second template parameter.

In the case of enable_if<true, int>, enable_if::type has a type of int.

like image 936
vmrob Avatar asked Dec 20 '12 04:12

vmrob


People also ask

Can we overload template functions with the same of arguments?

You may overload a function template either by a non-template function or by another function template. The function call f(1, 2) could match the argument types of both the template function and the non-template function.

How does overloading of template function occur?

The name of the function templates are the same but called with different arguments is known as function template overloading. If the function template is with the ordinary template, the name of the function remains the same but the number of parameters differs.

How are overloaded functions and function templates alike How are they different?

Function overloading is used when multiple functions do similar operations; templates are used when multiple functions do identical operations. Templates provide an advantage when you want to perform the same action on types that can be different.

What is the advantage of using template over function overloading?

the advantage of templates in a situation where you want to do the same set of operations on many different data types, is that the compiler will handle for you at compile time any possible new type you may create in the future that uses the templated function.

What happens when you overload a function template?

If you call the name of an overloaded function template, the compiler will try to deduce its template arguments and check its explicitly declared template arguments. If successful, it will instantiate a function template specialization, then add this specialization to the set of candidate functions used in overload resolution.

What is the difference between template and function template?

A template is a tool that reduces the efforts in writing the same code as templates can be used at those places. A template function can be overloaded either by a non-template function or using an ordinary function template. Function Overloading: In function overloading, the function may have the same definition, but with different arguments.

How does the compiler decide which functions to overload?

The compiler proceeds with overload resolution, choosing the most appropriate function from the set of candidate functions. Non-template functions take precedence over template functions. The following example describes this:

What is “function overloading”?

In Function Overloading “Function” name should be the same and the arguments should be different. Function overloading can be considered as an example of polymorphism feature in C++.


1 Answers

The first function is considered to be more specialized than the first.

The function

int foo(typename T::type)

could match

template <typename S,typename T> int foo(S s)

by using T::type as the value for parameter S, but

int foo(S s)

will not match

template <typename S,typename T> int foo(typename T::type)

because T cannot be deduced.

The logic is layed out in the C++03 standard in section 14.5.5.2, and in the C++11 standard in section 14.5.6.2.

Here is the idea: To see if one function is more specialized than another, you invent values for each template parameter for the first function, and then see if the second function could match the resulting signature. You also invent values for the template parameters of the second function, and see if the first function will match the resulting signature. If the second function can match the first one, then the second function can't be more specialized than the first one. If, in addition to that, the first function can't match the second, then the first must be more specialized than the second. That is the case you have.

like image 132
Vaughn Cato Avatar answered Oct 22 '22 04:10

Vaughn Cato