Consider the following snippet:
template <class T>
struct remove_pointer
{
};
template <class T>
struct remove_pointer<T*>
{
typedef T type;
};
template <typename T>
T
clone(const T& v)
{
return v;
}
template <typename T, typename U = typename remove_pointer<T>::type>
T
clone(const U& v)
{
return new U(v);
}
int main()
{
auto foo = clone<double>(42.0);
return 0;
}
This code generates compilation errors:
In function 'int main()':
30:34: error: call of overloaded 'clone(double)' is ambiguous
30:34: note: candidates are:
14:1: note: T clone(const T&) [with T = double]
22:1: note: T clone(const U&) [with T = double; U = double]
Why is the compiler deriving T=double, U=double
in line 22? I thought it only should pass if T
is a pointer type.
Compiler deduced U=double
and didn't use your default argument at all. I think that you can try to have two different overloads for your clone
function based on this answer.
Your example might look like this:
#include <iostream>
#include <type_traits>
template <typename T>
T
clone(const T& v, typename std::enable_if<!std::is_pointer<T>::value >::type* = 0)
{
std::cout << "non ptr clone" << std::endl;
return v;
}
template <typename T>
T
clone(const T v, typename std::enable_if<std::is_pointer<T>::value >::type* = 0)
{
std::cout << "ptr clone" << std::endl;
using noptrT = typename std::remove_reference<decltype(*v)>::type;
return new noptrT(*v);
}
int main()
{
auto foo = clone<double>(42.0);
std::cout << foo << std::endl;
double* ptr = new double(69.69);
auto bar = clone<double*>(ptr);
std::cout << *bar << std::endl;
delete ptr;
delete bar;
return 0;
}
Note that this solution also allows you to pass a function pointer
void fun() {}
...
clone<void(*)()>(fun);
which will result in compilation error (new cannot be applied to function type).