用于访问struct成员的模板函数

时间:2015-11-13 20:43:07

标签: c++ templates struct

我有一个结构,其中包含其他结构以及主要数据类型。我希望能够使用模板函数访问每个成员,包括主结构中包含的结构的成员。

例如:

struct B {
    int y;
    int z;
};

struct A {
    int x;
    B b;
};

template <typename TMember>
bool doSomething(A *a, TMember member) {

    a->*member = 5;  // some code accessing member

}

// Then access it with:

doSomething(&myA, &A::x);

// and likewise

doSomething(&myA, &A::b.y);

然而,第二个将不会编译并抛出一个&#34;对象缺少引用&#34;错误。我认为它是因为A没有会员b.y?

无论如何都要获得我想要的功能或者需要编写不同的功能吗?

(请注意,这只是一个示例,我所拥有的代码包含更大的结构,并且比仅编写第二个函数节省了更多时间。)

谢谢!

5 个答案:

答案 0 :(得分:2)

那里有几个问题。

更容易的是A::x格式错误:您需要指向成员的指针,并且需要address-of运算符。 doSomething(&myA, &A::x)可以正常使用。

第二个是棘手的,因为在C ++中没有办法形成指向成员成员的指针。除非你想用offsetof做一些hacky,非类型安全的东西,否则你需要比指针更强大的东西。例如,您可以传入一个lambda,它返回对成员的引用:

template <typename TAccessor>
void doSomething(A *a, TAccessor accessor){

    accessor(a) = 5;
}

int main()
{
    A myA;
    doSomething(&myA, [](A* a)->int&{ return a->b.y; });
}

显然,这会留下一些需要的东西,可读性。

编辑:哦,如果您的最终解决方案基于成员指针,请参考101010的建议并使模板参数专门成为成员指针模板参数。它不仅可能更有效,而且更自我记录,如果你陷入困境,编译器错误会更加清晰十倍。

答案 1 :(得分:2)

你不能指向指向成员的指针(它是forbidden by the language)。但是,您可以继续访问指向成员的指针。

如果我们使用递归函数来概括访问,该函数一直在调用指向成员的指针:

template <typename C, typename T>
decltype(auto) access(C& cls, T C::*member) {
    return (cls.*member);
}

template <typename C, typename T, typename... Mems>
decltype(auto) access(C& cls, T C::*member, Mems... rest) {
    return access((cls.*member), rest...);
}

然后我们可以编写doSomething来获取任意数量的指针:

template <typename... Members>
void doSomething(A *a, Members... mems) {
    access(*a, mems...) = 5;
}

并称之为:

A myA;
doSomething(&myA, &A::x);
doSomething(&myA, &A::b, &B::y);

答案 2 :(得分:1)

实现这一目标的一种简单方法是使用函数指针作为模板函数的参数:

// Example program
#include <iostream>
#include <string>

struct B{
    int y;
    int z;
};

struct A{
    int x;
    B b;
};

int& get1( A& a ) { return a.x; }
int& get2( A& a ) { return a.b.y; }

template <typename T>
bool doSomething(A *a, T& (*getter)( A& ) ){

    T& attr = (*getter)( *a ); // get reference to the attribute
    attr = 5;  // modify the attribute
    return true;
}


int main()
{
    A myA;

    doSomething(&myA, &get1);
    doSomething(&myA, &get2);
}

答案 3 :(得分:0)

在你的例子中,你缺少&amp;在会员参考。 A :: b.y是未解决的问题。 A :: b :: y和A :: B :: y也不好。你可以使用B :: y。

doSomething(&myA, &B::y);

但它不是A的成员,这可能导致错误的行为。或者可能没有。所以考虑用

替换
template <class TOwner, typename TMember>
bool doSomething(TOwner * owner, TMember member);

另外,我在代码中看不到任何std::atomic。你的意思是整数类型而不是原子吗?

答案 4 :(得分:0)

您可以通过将指针传递给下面的成员变量来执行您想要的类成员变量:

template <typename T>
void doSomething(A *a, T A::*member){ 
  a->*member = 5;
}

LIVE DEMO