免责声明这或多或少是“自动的”。
我希望你喜欢模板;)(这也需要 C++11,最值得注意的是因为它使用元组和可变参数模板。)
另外,我要感谢 Rapptz 用索引技巧解决了我对元组的递归/迭代。
所以,这是我的两个想法的混合。第一个是我之前在评论中发布的。这个想法的问题在于,您只能将所有成员变量放在一个非常不方便的元组中。我有另一个想法没有成功,因为它涉及与 Adder 模板的循环依赖。
所以最后的想法是你从加法器模板继承,它假设你有一个静态成员变量(元组类型),你在其中放置指向要添加的成员变量的指针。并且您继承的默认实现创建了一个类型为 T 的新变量,迭代元组的参数并对它们进行成员明智的添加。
您可以在这里看到它的实际效果。请注意,您应该能够以与 operator+ 相同的方式添加对 tostring(或 operator <<)的支持(而不是像我那样手动添加),并且对于从 initializer-list 进行构造也是如此。
#include <iostream>
#include <string>
#include <type_traits>
#include <tuple>
template<size_t... Ns>
struct indices {};
template<size_t N, size_t... Ns>
struct build_indices : build_indices<N-1, N-1, Ns...> {};
template<size_t... Ns>
struct build_indices<0, Ns...> : indices<Ns...> {};
template<typename T, typename Tuple, size_t... Indices>
void memberWiseSum(T& lhs, T& rhs, T& sum, const Tuple& typeInfo, indices<Indices...>)
{
using expander = int[];
(void)expander{((sum.*std::get<Indices>(typeInfo) = lhs.*std::get<Indices>(typeInfo) + rhs.*std::get<Indices>(typeInfo)), 0)...};
}
template<typename T>
struct Adder
{
T operator+(Adder<T>& rhs)
{
T sum;
memberWiseSum(*static_cast<T*>(this), *static_cast<T*>(&rhs), *static_cast<T*>(&sum), T::typeInfo, build_indices<std::tuple_size<decltype(T::typeInfo)>::value>{});
return sum;
}
};
struct Vec4: public Adder<Vec4>
{
float x,y,z,w;
std::string toString()
{
return "{" + std::to_string(x) + ", " + std::to_string(y) + ", " + std::to_string(z) + ", " + std::to_string(w) + "}";
}
const static std::tuple<decltype(&Vec4::x), decltype(&Vec4::y), decltype(&Vec4::z), decltype(&Vec4::w)> typeInfo;
};
decltype(Vec4::typeInfo) Vec4::typeInfo(&Vec4::x, &Vec4::y, &Vec4::z, &Vec4::w);
struct Vec2: public Adder<Vec2>
{
float x,y;
std::string toString()
{
return "{" + std::to_string(x) + ", " + std::to_string(y) + "}";
}
const static std::tuple<decltype(&Vec2::x), decltype(&Vec2::y)> typeInfo;
};
decltype(Vec2::typeInfo) Vec2::typeInfo(&Vec2::x, &Vec2::y);
struct VertexData: public Adder<VertexData>
{
Vec4 vertex;
Vec2 texCoord;
std::string toString()
{
return "{" + vertex.toString() + ", " + texCoord.toString() + "}";
}
const static std::tuple<decltype(&VertexData::vertex), decltype(&VertexData::texCoord)> typeInfo;
};
decltype(VertexData::typeInfo) VertexData::typeInfo(&VertexData::vertex, &VertexData::texCoord);
int main()
{
VertexData vd1; vd1.vertex.x = 1; vd1.vertex.y = 2; vd1.vertex.z = 3; vd1.vertex.w = 4;
vd1.texCoord.x = 5; vd1.texCoord.y = 6;
VertexData vd2; vd2.vertex.x = 1; vd2.vertex.y = 2; vd2.vertex.z = 3; vd2.vertex.w = 4;
vd2.texCoord.x = 5; vd2.texCoord.y = 6;
VertexData vd3 = vd1 + vd2;
std::cout << vd3.toString() << std::endl;
return 0;
}
最后,正如评论中和 Yakk 所提到的,真正的自动解决方案需要一个反射系统(很像 C# 所拥有的),但目前 C++ 中不存在。