Search code examples
c++templatesconstructorc++14

Need help understanding templated constructors in templated classes


I'm a template newb. This code (you can run it on here on cpp.sh) has a template constructor in a template class. I pulled it from code that wants a pointer to the memory array of a vector to send/receive data in a radio, and the vector can be instantiated with different data types (short, long, double). The main code successfully passes references to two different types (short and double) to the function aargh's ptr argument.

// Example program
#include <iostream>
#include <vector>

template <typename T>
class ref_vector
{
public:

    /*!
     * Create a reference vector from a pointer.
     * \param ptr a pointer to a chunk of memory
     */
    template <typename Ptr>
    ref_vector(Ptr* ptr) : _ptr(T(ptr))
    {
        /* NOP */
    }

private:
    const T _ptr;
};


void aargh(const ref_vector<void*>& ptr, const char *s) {
    std::cout << "aargh " << s << std::endl;
}

int main()
{
    std::vector<short> bozo(20);
    std::vector<double> clown(20);
    aargh(&bozo.front(), "is short");
    aargh(&clown.front(), "is double");
}

The program compiles and runs with C++14 without explicitly specifying a type for the ref_vector constructor. I don't understand what the template declaration of the constructor is doing, and how the compiler is inferring the type of Ptr in ref_vector. I don't know the terminology to describe what is going on here so I can search for an explanation.


Solution

  • I don't understand what the template declaration of the constructor is doing, and how the compiler is inferring the type of Ptr in ref_vector.

    aargh(&bozo.front(), "is short");
    aargh(&clown.front(), "is double");
    

    You pass a short* and double* to a ref_vector<void*> constructors.

    The constructors takes any pointer since they will be instantiated from a function template crafted to do so ...

    template <typename Ptr>
    ref_vector(Ptr* ptr) : _ptr(T(ptr)) {}
    //         ^^^^ any pointer will do
    

    ... which results in these two constructors being instantiated:

    ref_vector(short* ptr) : _ptr((void*) ptr) {}
    ref_vector(double* ptr) : _ptr((void*) ptr) {}
    

    It thereby converts whatever pointer it gets into a void* via the function style cast T(ptr) (since T is void*).