Partial specialization of a class template member function

201 Views Asked by At

I have defined two class templates, class two_val and class trait_vector as follows:

template<class T>
class two_val{
    private:
        T first_val;
        T second_val;
               
    public:

        two_val() :
            first_val {},
            second_val {}
        {}
        
        T get_first() const {return first_val;}
};

and:

template<class T>
class trait_vector{
    private:
    
        std::vector<T> vec;
                
    public:
        trait_vector() :
            vec {}
        {}
};

Now, for the case that I have a trait_vector of two_val<T>s of any class T, I would like to provide a function that returns me the trait_vector<T> of the respective first_vals.

I managed to implement this by specializing the class trait_vector as follows:

template<class T>
class trait_vector<two_val<T>>{
    private: 
        std::vector<two_val<T>> vec;
                
    public:
        trait_vector() :
            vec {}
        {}
        
        trait_vector<T> get_first() {
            trait_vector<double> result {};
            for(unsigned i=0; i < vec.size(); ++i){
                result.vec.push_back(vec[i].get_first());
            }
            return result;

        }
};

But I would like to avoid copy and pasting the entire rest of the class. It feels like there should be a shorter solution (especially since the classes I'm actually working with are much bigger).

However, every direct solution that I tried ran into the problem that function templates cannot be partially specialized. This answer explains how to use a helper class for the desired function in a related case. However, I did not manage the transfer to my situation.

1

There are 1 best solutions below

5
Jarod42 On BEST ANSWER

First create a trait is_two_val:

template <typename T> struct is_two_val : std::false_type {};
template <typename T> struct is_two_val<two_val<T>> : std::true_type {};

Having typedef in your two_val class might help (else might be done with externl traits)

template<class T>
class two_val{
public:
    using type = T;
// ...
};

then you might SFINAE or requires (C++20) for your member with that traits:

template<class T>
class trait_vector{
private: 
    std::vector<T> vec;
                
public:
    trait_vector() : vec {} {}
        
    auto get_first() requires (is_two_val<T>::value)
    {
        trait_vector<typename T::type> result{};
        result.reserve(vec.size());
        for(const auto& p : vec){
            result.vec.push_back(p.get_first());
        }
        return result;
    }
};