我想迭代POD结构的成员,我想象它可以工作的唯一方法是使用模板。但为此,我需要一些能解决这个问题的东西:
template <typename ...T>
void bar(T ...t) {
/* ... do something ... */
}
template <typename T>
void foo(T t) {
bar(magical_decompose(t));
}
struct MyPod {
int i;
double d;
float f;
};
int main() {
MyPod myPod = {1,2,3};
foo(myPod);
}
应该通过模板将 bar(magical_decompose(t));
转换为bar(t.i, t.d, t.f)
。我不知道是否有可能,但我希望它是可能的。有没有人知道如何才能做到这一点?
答案 0 :(得分:3)
您要找的是反射。
目前还没有语言的内置支持。 C ++委员会中有一个working group,有些库使用宏或其他技巧以某种方式模拟它。我能想到的最简单的解决方案是使用宏,它在Boost.Fusion中使用BOOST_FUSION_ADAPT_STRUCT宏实现。
答案 1 :(得分:2)
可以确定结构是否包含某些成员名称(使用SFINAE技巧),并通过offsetof
确定其顺序。例如,如果您知道成员名称都只有一个字母长,那么您可以使用这些技巧来枚举结构成员(尽管生成的代码至少不可维护)。
但是,据我所知,不可能简单地枚举元素名称而不了解它们。 Boost.MPL(元编程库),可以说是元编程最复杂的用途之一,并没有提供这样的设施,作者在an academic paper中注意到这是不可能的:
不幸的是,这种安排不容易受到C ++给我们的编译时类型内省功能的影响: 没有办法知道成员的名字是什么,即使我们假设他们根据他们的名字命名 对于上述某些惯例,没有办法知道有多少成员。
(对于具有任意多个成员的结构,最后一句是正确的,但是通过将成员数限制为例如20,您可以使用SFINAE解决固定命名方案的问题。)
答案 2 :(得分:1)
如果您愿意明确描述结构成员,您可能会接近您想要的结果。
#include <iostream>
#include <tuple>
#include <functional>
using namespace std;
struct test
{
int i = 121;
double j = 234.0;
string k = "Some k";
};
struct anotherStruct
{
double t = 121.8;
};
struct undescribedStruct
{
string t = "Some undescribed";
};
tuple<int&, double&, string&> struct_as_tuple(test& t)
{
return tie( t.i, t.j, t.k);
}
tuple<double&> struct_as_tuple(anotherStruct& t)
{
return tie( t.t );
}
//make_indices && Co thanks to sigidagi
//see http://cpptruths.blogspot.de/2012/06/perfect-forwarding-of-parameter-groups.html
template<unsigned...> struct index_tuple{};
template<unsigned I, typename IndexTuple, typename... Types>
struct make_indices_impl;
template<unsigned I, unsigned... Indices, typename T, typename... Types>
struct make_indices_impl<I, index_tuple<Indices...>, T, Types...>
{
typedef typename
make_indices_impl<I + 1,
index_tuple<Indices..., I>,
Types...>::type type;
};
template<unsigned I, unsigned... Indices>
struct make_indices_impl<I, index_tuple<Indices...> >
{
typedef index_tuple<Indices...> type;
};
template<typename... Types>
struct make_indices
: make_indices_impl<0, index_tuple<>, Types...>
{};
void bar()
{
std::cout << endl;
}
template <typename T, typename... Args>
void bar(T&& t, Args&&... args)
{
std::cout << "T: [" << t << "] ";
return bar(forward<Args>(args)...);
}
template <unsigned... Indices, class... Args>
void foo_forward_call_impl(index_tuple<Indices...>,
std::tuple<Args...> tuple )
{
return bar(std::get<Indices>(tuple)...);
}
template<class... Args>
void foo_forward_call(std::tuple<Args...> tuple )
{
typedef typename make_indices<Args...>::type Indices;
return foo_forward_call_impl(Indices(), tuple);
}
template <typename T>
void foo(T&& t)
{
return foo_forward_call( struct_as_tuple(t) );
}
int main()
{
test t1;
foo(t1);
anotherStruct t2;
foo(t2);
undescribedStruct t3;
//will error foo(t3);
// your code goes here
return 0;
}
您基本上必须为每个受支持的类型的struct成员提供元组构造(请参阅struct_as_tuple)。
foo然后从传入的类型中生成元组并将其传递给元组展开实现。
这不是你想要的,但它是我能想象的最接近它......
答案 3 :(得分:0)
正如@sbabbi指出的那样,目前没有内置语言支持,所以它不会免费提供,你必须自己做点什么。在c ++ 14中,尽力而为:
#include <type_traits>
// specialize this trait to register T
template<class T>
struct decompose;
template<class T, class F>
void magical_decompose(T&& t, F&& f)
{
decompose<std::decay_t<T>>::apply(t, f);
}
template <typename ...T>
void bar(T ...t) {
}
template <typename T>
void foo(T t) {
magical_decompose(t, [](auto&&... ts)
{
bar(static_cast<decltype(ts)>(ts)...);
});
}
struct MyPod {
int i;
double d;
float f;
};
// register MyPod
template<>
struct decompose<MyPod>
{
// works for both const & non-const
template<class T, class F>
static void apply(T& t, F& f)
{
f(t.i, t.d, t.f);
}
};
int main() {
MyPod myPod = {1,2,3};
foo(myPod);
}
这是非常通用的,只为您感兴趣的类型decompose
专门设置T
,它可以优雅地发出声音。