Search code examples
c++c++17variadic-templatestype-deduction

template type deduction in a member function of a templated class


the deduction fails in the first line in the main function, how to solve that without adding additional template parameters

#include <iostream>

template <typename T>
class myVec{
    size_t _size{};
    size_t capacity{};
    T* data{};

public:
    myVec(size_t size = 0, T value = T{}):_size{size}, capacity{2 * _size}{
        data = new T[capacity];
        for(size_t index{}; index < _size; index++)
            data[ index ] = T{};
    }

    template <typename ... Ts>
    myVec( Ts&& ... vals):myVec{ sizeof...(vals)}{


        size_t index{};
        ((data [ ++index ] = vals),...);
    }

    ~myVec(){
        delete[] data;
    }
    size_t size( ){
        return _size;
    }
    /*the rest */

};

int main(){
    myVec vec {1, 32, 5, 6};

    for(size_t index{}; index < vec.size(); ++index )
        std::cout << vec[ index ] << " ";
}

Solution

  • Class templates are only able to implicitly deduce the class template argument if it matches a constructor exactly, e.g.:

    template <typename T>
    class myVec
    {
        ...
        myVec(int, T); // T can be deduced since it's from the class template
        ...
    };
    ...
    myVec(5,5); // deduces myVec<int>
    

    On the other hand, types from a constructor template do not participate in the deduction directly -- since the deduced types may not necessarily be the same type as the class template:

    template <typename T>
    class myVec
    {
        ...
        template <typename U>
        myVec(int, U); // U may not be the same as T!
        ...
        template <typename...Ts>
        myVec(Ts&&...); // All 'Ts' types may not be the same as 'T'
        ...
    };
    

    The way to work around this is with user-defined deduction guides. These allow you to defined what type is deduced when faced with otherwise ambiguous constructor expressions. In your case, you are probably looking for something like:

    template <typename...Ts> 
    myVec(Ts...) -> myVec<std::common_type_t<Ts...>>;
    

    Note: std::common_type_t is used to get the common type of all the variadic types. It is defined in the <type_traits> header.