Reputation: 769
Based on my understanding of the C++'s partial ordering algorithm, it seems that the first one is strictly a subset of the second definition. Therefore, whenever both can be chosen, the first one should be preferred. But I am getting the following error message:
p_o.cpp:13:10: error: call to 'f' is ambiguous
return f<R>(args...);
^~~~
p_o.cpp:17:12: note: in instantiation of function template specialization 'f<int, double, int>' requested here
auto a = f<int>(0.3, 1);
^
p_o.cpp:7:3: note: candidate function [with T = int, Ts = <>]
T f(T a, Ts ...args) {
^
p_o.cpp:12:3: note: candidate function [with R = int, T = int, Ts = <>]
R f(T a, Ts ...args) {
^
1 error generated.
Could someone please explain where am I going wrong? I am new to meta-programming.
#include <tuple>
using namespace std;
template <typename T, typename ...Ts>
T f(T a, Ts ...args) {
return a;
}
template <typename R, typename T, typename ...Ts>
R f(T a, Ts ...args) {
return f<R>(args...);
}
int main() {
auto a = f<int>(0.3, 1);
static_assert(is_same<int, decltype(a)>::value);
}
Upvotes: 3
Views: 69
Reputation: 6086
You can boil down your offending case to the following:
f<int>(1);
Which can be interpreted as a call to:
R f<R, T, Ts...>(T, Ts...) // with `R = int`, `T=int` and `Ts = <>`
or a call to:
T f<T, Ts>(T, Ts...) // with `T = int` and `Ts = <>`
Note that the more specialized reasoning of partial template ordering applies on argument types and here, they both are the same therefore, the 2 overloads are considered equally valid for your call which leads to the ambiguity.
To resolve that you need something to disqualify one of the two overloads. It seems you want to extract the first member of your pack matching the requested type... To do so you could use a SFINAE based design:
template< typename R, typename T, typename... Ts >
std::enable_if_t< std::is_same< R, T >::value, R > f( T a, Ts... )
{
return a;
}
template< typename R, typename T, typename... Ts >
std::enable_if_t< ! std::is_same< R, T >::value, R > f( T, Ts... args )
{
return f< R >( args... );
}
Upvotes: 2