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_val
s.
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.
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;
}
};