struct Person {
std::string name;
int age;
};
int main() {
Person joe{"Joe", 30};
std::cout << to_json(joe);
}
def to_json(obj):
members = []
for member in obj.__dict__:
members.append('"' + member + '" : ' +
str(getattr(obj, member)))
return '{' + ', '.join(members) + '}'
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
print to_json(Person("John", 30))
Of course, this is a simplified version and it only handles objects.template <typename T>
std::string to_json(T const& obj) {
std::vector<std::string> members;
for (std::string const& member : obj.__members__()) // ???
members.push_back('"' + member + "\" : " +
to_json(obj.__get__(member))); // ???
return "{" + boost::algorithm::join(members, ", ") + "}";
}
We won't talk about reflection in this talk, because it's an introduction only.class A: pass
class B: pass
class C: pass
def register(classes):
for c in classes:
print "Registering " + c.__name__
register([A, B, C])
This works because types are first class citizensvoid register_(std::vector<...> const& classes) {
for (auto c : classes) {
std::cout << "Registering " << c.name()
<< ", which is of size " << sizeof(c) << std::endl;
static_assert(sizeof(c) <= 1000, "");
}
}
int main() {
std::vector<...> classes{A, B, C};
register_(classes);
}
Type packed_triple(std::vector<Type> types) {
std::sort(types.begin(), types.end(), [](auto const& a,
auto const& b) {
return a.alignment() > b.alignment();
});
return Type{Triple<types[0], types[1], types[2]>};
}
int main() {
std::vector<Type> types{A, B, C};
Packed = packed_triple(types); // get the type
Packed triple{...}; // define an object of that type
}
Notice how this sort of computation is completely compile-time. The inputs are
types and the output is a type too.double, double, double
from_spherical(double rho, double theta, double phi) {
double x = rho * std::sin(theta) * std::cos(phi);
double y = rho * std::sin(theta) * std::sin(phi);
double z = rho * std::cos(theta);
return (x, y, z);
}
double (x, y, z) = from_spherical(3, 16.5, 25.5);
struct {
double _0; double _1; double _2;
} xyz = from_spherical(3, 16.5, 25.5);
double x = xyz._0,
y = xyz._1,
z = xyz._2;
struct {
Fish _0; Cat _1; Dog _2; // notice the members have different types
} animals = my_animals();
Fish fish = animals._0;
Cat cat = animals._1;
Dog dog = animals._2;
void register_(std::vector<...> const& classes) {
for (auto c : classes) {
std::cout << "Registering " << c.name()
<< ", which is of size " << sizeof(c) << std::endl;
static_assert(sizeof(c) <= 1000, "");
}
}
int main() {
std::vector<...> classes{A, B, C};
register_(classes);
}
void register_(std::vector<std::type_info> const& classes) {
for (auto c : classes) {
std::cout << "Registering " << c.name()
<< ", which is of size " << sizeof(c) << std::endl;
static_assert(sizeof(c) <= 1000, "");
}
}
int main() {
std::vector<std::type_info> classes{typeid(A), typeid(B),
typeid(C)};
register_(classes);
}
1. We need the size of each type, not that of std::type_info itself.
2. We can't store std::type_info in a vector, because not Copyable
3. Even if type_info provided a size() method, it would only be available at runtime.template <typename T>
struct static_type_info {
using type = T;
};
void register_(std::vector<...> const& classes) {
for (auto c : classes) {
using T = typename decltype(c)::type;
std::cout << "Registering " << typeid(T).name()
<< ", which is of size " << sizeof(T) << std::endl;
static_assert(sizeof(T) <= 1000, "");
}
}
int main() {
std::vector<...> classes{static_type_info<A>{},
static_type_info<B>{},
static_type_info<C>{}};
register_(classes);
}
We're close, but for this to work we'd need to be able to store objects
of different types in the vector, which we can't do.template <typename ...TypeInfos>
void register_(std::tuple<TypeInfos...> const& classes) {
for (auto c : classes) {
using T = typename decltype(c)::type;
std::cout << "Registering " << typeid(T).name()
<< ", which is of size " << sizeof(T) << std::endl;
static_assert(sizeof(T) <= 1000, "");
}
}
int main() {
std::tuple<static_type_info<A>,
static_type_info<B>,
static_type_info<C>> classes;
register_(classes);
}
template <typename ...TypeInfos>
void register_(std::tuple<TypeInfos...> const& classes) {
auto f = [](auto c) {
using T = typename decltype(c)::type;
std::cout << "Registering " << typeid(C).name()
<< ", which is of size " << sizeof(C) << std::endl;
static_assert(sizeof(C) <= 1000, "");
};
f(std::get<0>(classes));
f(std::get<1>(classes));
f(std::get<2>(classes));
// ...
}
Recapitulating:
1. We create a static type info struct to hold type information at compile-time
2. We create a tuple of these type infos
3. We manipulate the elements of the tuple as normal objects to achieve our goalEquivalent to
http://ldionne.com http://github.com/ldionne http://github.com/boostorg/hana