Reputation: 289
I want to be able to do something like this for example.
std::vector<std::vector<int>> e = {{ 1 },{ 2 }};
std::vector<std::vector<double>> q = {{1.5},{2.5}};
q = vector_cast<double>(e);
But also have vector_cast be able to handle any number of nested vectors.
Here is my attempt at this. The code works if you comment out the line that is labled does not work. The problem is I need help implementing the vector_cast function.
#include <iostream>
#include <vector>
#include <algorithm>
#include <type_traits>
//Prints nested vectors
template<typename T1>
std::ostream& operator<<(std::ostream& stream, std::vector<T1> r){
if(r.size() == 0){
return stream;
}
else{
stream << "(";
for(int i = 0; i < r.size(); i++){
if(i < (r.size() - 1)){
stream << r[i] << ", ";
}
else{
stream << r[i] << ")";
}
}
}
return stream;
};
//Adds nested vectors
template <typename T1, typename T2>
struct vector_common_type : std::common_type<T1, T2> { };
template <typename T1, typename T2>
struct vector_common_type<std::vector<T1>, std::vector<T2>> {
using type = std::vector<typename vector_common_type<T1,T2>::type>;
};
template <typename T1, typename T2,
typename R = std::vector<typename vector_common_type<T1,T2>::type>>
R operator+(const std::vector<T1>& l, const std::vector<T2>& r)
{
R ans;
std::transform(l.begin(),
l.begin() + std::min(l.size(), r.size()),
r.begin(),
std::back_inserter(ans),
[](const T1& lhs, const T2& rhs){ return lhs + rhs; });
return ans;
}
//supposed to cast nested vectors
template <typename T1, typename T2>
struct vector_casting : std::condition<true,T1, T2> { };
template <typename T1, typename T2>
struct vector_casting<std::vector<T1>, std::vector<T2>> {
using type = std::vector<typename vector_casting<T1,T2>::type>;
};
template <typename T1, typename T2,
typename R = std::vector<typename vector_casting<std::vector<T1>,T2>::type>>
R vector_cast(const std::vector<T2>& r){
R l(r.begin(),r.end());
return l;
};
int main(){
std::vector<std::vector<int>> e = {{ 1 },{ 1 }};
std::vector<std::vector<double>> q = {{1.5},{2.5}};
//This works
q = q + q;
//This does not work
q = e;//<- needs cast, but my vector_cast does not work
std::cout << q << std::endl;
return 0;
}
Upvotes: 1
Views: 280
Reputation:
With vector type detection you might do:
#include <iostream>
#include <vector>
// is_vector
// =========
namespace Detail {
template<typename T>
struct is_vector_test {
static constexpr bool value = false;
};
template<typename ... Types>
struct is_vector_test<std::vector<Types...>> {
static constexpr bool value = true;
};
}
template<typename T>
struct is_vector : Detail::is_vector_test<typename std::decay<T>::type>
{};
// vector_cast
// ===========
namespace Detail
{
template <typename R, typename U, bool = is_vector<U>::value>
struct vector_cast_implementation;
// Elementary
template <typename R, typename T>
struct vector_cast_implementation<R, T, false>
{
typedef T value_type;
typedef R result_type;
static result_type apply(const value_type& value){
// Simple Conversion
return value;
}
};
// Vectors
template <typename R, typename U>
struct vector_cast_implementation<R, std::vector<U>, true>
{
private:
typedef vector_cast_implementation<R, U> base_cast;
public:
typedef std::vector<typename base_cast::value_type> value_type;
typedef std::vector<typename base_cast::result_type> result_type;
static result_type apply(const value_type& value){
result_type result;
result.reserve(value.size());
for(const auto& element : value)
result.push_back(base_cast::apply(element));
return result;
}
};
}
template <typename R, typename T>
typename Detail::vector_cast_implementation<R, std::vector<T>>::result_type
vector_cast(const std::vector<T>& sequence){
return Detail::vector_cast_implementation<R, std::vector<T>>::apply(sequence);
}
// test
// ====
int main() {
std::vector<std::vector<std::vector<double>>> v3 = {
{{ 0.0 , 0.1, 0.2 },
{ 1.0 , 1.1, 1.2 },
{ 2.0 , 2.1, 2.2 }},
{{ 10.0 , 10.1, 10.2 },
{ 11.0 , 11.1, 11.2 },
{ 12.0 , 12.1, 12.2 }},
};
auto r3 = vector_cast<int>(v3);
for(const std::vector<std::vector<int>>& r2 : r3) {
for(const std::vector<int>& r1 : r2) {
for(int e : r1)
std::cout << e << " ";
}
std::cout << "\n";
}
}
To determine a common type R for a binary vector operation you might do:
// vector_common_type
// ==================
namespace Detail
{
template <typename U,typename V, bool = is_vector<U>::value, bool = is_vector<V>::value>
struct vector_common_type_implementation;
// Elementary
template <typename U, typename V>
struct vector_common_type_implementation<U, V, false, false>
{
typedef typename std::common_type<U, V>::type type;
};
// Vectors
template <typename U, typename V>
struct vector_common_type_implementation<std::vector<U>, std::vector<V>, true, true>
{
typedef typename vector_common_type_implementation<U, V>::type type;
};
}
template <typename U, typename V>
struct vector_common_type;
template <typename U, typename V>
struct vector_common_type<std::vector<U>, std::vector<V>>
: public Detail::vector_common_type_implementation<std::vector<U>, std::vector<V>>
{};
Upvotes: 1