c++c++11templatesdefault-template-argument

Special overload for pointer types


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.


Solution

  • 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).