Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it valid to overload function with extra non-deducible template parameter?

The following code compiles and works fine with gcc (9), clang (11) and msvc (16.28):

template <class A>
struct X {
    A a;

    constexpr X(A a) : a{a} { }
};

template <class A>
constexpr auto fn(X<A> const& x) {
    return X<A>(x.a - 1);
}


template <class Xs, class A>
constexpr auto fn(X<A> const& x) {
    return Xs(x.a - 1);
}

constexpr X<int> x1{3};
constexpr auto x2 = fn(x1);
constexpr auto x3 = fn<X<double>>(x1);

There are two fn functions with identical declarations except for the extra Xs parameter in the second one.

I'd like to be sure that this is standard-accepted and not something that these compilers provide as extra? Since all 3 do, I'd guess this would be standard, but you never know.

I'd also like to know if my assumptions as to why this work/would be standard are correct:

  • in the call fn(x1), Xs cannot be deduced so the second overload of fn is discarded gently (SFINAE?)?
  • in the call fn<Xs>(x1), the first overload would then be fn(X<X<int>>) which does not match the argument x1, thus the first overload is also discarded?
like image 640
Holt Avatar asked Aug 09 '21 07:08

Holt


People also ask

Can a template parameter be a function?

A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.

What is template argument deduction?

Template argument deduction is used when selecting user-defined conversion function template arguments. A is the type that is required as the result of the conversion. P is the return type of the conversion function template.

What happens if you overload a function template?

You may overload a function template either by a non-template function or by another 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.

How do you overload a function in C++?

Overloading function templates (C++ only) You may overload a function template either by a non-template function or by another 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.

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 functional overloading in Python?

Function overloading in python can be of two types one is overloading built-in functions and overloading the custom or user-defined functions in python. We will have a look into both of them in the below sections. In general, not every programming language supports function overloading but in this case, python supports functional overloading.


1 Answers

There are two fn functions with identical declarations except for the extra Xs parameter in the second one.

That's fine, you can overload function templates using different arguments or different template arguments.

  • in the call fn(x1), Xs cannot be deduced so the second overload of fn is discarded gently (SFINAE?)?

Yes, except it's not SFINAE, but overload resolution. The S in SFINAE stands for substitution. When a template argument can't be deduced, no substitution takes place.

It's described in [temp.over]/1:

... For each function template, if the argument deduction and checking succeeds, the template-arguments (deduced and/or explicit) are used to synthesize the declaration of a single function template specialization which is added to the candidate functions set to be used in overload resolution.

With regard to the second bullet (fn<X<double>>(x1)), both templates can synthesize a valid declaration, but X<int> isn't convertible to X<X<double>>, so the second overload is selected as the only viable one.

Note: when multiple template overloads are viable, partial ordering is performed to determine the most specialized template.

like image 160
rustyx Avatar answered Nov 02 '22 06:11

rustyx