The void** casting is a bit close to UB, so I'll probably avoid that.
I've come up with a nice kludge to wrap the C vector with zero overhead
(GCC optimizes the C++ wrapper completely away). This should have
well-defined behavior with C++11.
#include <boost/iterator/transform_iterator.hpp>
#include <iostream>
#include <memory>
typedef struct {
void** data;
unsigned int length;
} Vector;
typedef struct {
int i;
} S1;
typedef struct {
const char* s;
} S2;
static const int elem_count = 5;
static const char* int_str[] = {"0", "1", "2", "3", "4"};
void initTestVecS1(Vector& vec) {
vec.data = static_cast<void**>(malloc(sizeof(void*) * elem_count));
vec.length = elem_count;
for(int i = 0; i < elem_count; i++) {
vec.data[i] = new S1{i};
}
}
void initTestVecS2(Vector& vec) {
vec.data = static_cast<void**>(malloc(sizeof(void*) * elem_count));
vec.length = elem_count;
for(int i = 0; i < elem_count; i++) {
vec.data[i] = new S2{int_str[i]};
}
}
template<typename node_type>
node_type& cast_node(void* ptr) {
return *static_cast<node_type*>(ptr);
}
template<typename node_type>
struct VectorWrapper {
Vector data;
auto begin() {
return boost::make_transform_iterator(
&data.data[0], cast_node<node_type>);
}
auto end() {
return boost::make_transform_iterator(
&data.data[data.length], cast_node<node_type>);
}
static VectorWrapper<node_type>& toWrapper(Vector& vec) {
return *reinterpret_cast<VectorWrapper<node_type>*>(&vec);
}
};
int main() {
Vector v1; initTestVecS1(v1);
auto vw1 = VectorWrapper<S1>::toWrapper(v1);
for(int i = 0; i < elem_count; i++)
std::cout << static_cast<S1*>(v1.data[i])->i << " ";
std::cout << std::endl;
for(const auto& elem : vw1) std::cout << elem.i << " ";
std::cout << std::endl;
Vector v2; initTestVecS2(v2);
auto vw2 = VectorWrapper<S2>::toWrapper(v2);
for(const auto& elem : vw2) std::cout << elem.s << " ";
std::cout << std::endl;
}