可以定义指向成员的指针,稍后再使用它:
struct foo
{
int a;
int b[2];
};
int main()
{
foo bar;
int foo::* aptr=&foo::a;
bar.a=1;
std::cout << bar.*aptr << std::endl;
}
现在我需要一个指向数组特定元素的指针,所以通常我会写一个
int foo::* bptr=&(foo::b[0]);
但是,编译器只是抱怨"invalid use of non-static data member 'foo::b'
“
是否可以这样做(或者至少没有工会)?
编辑:我需要一个指向数组特定元素的指针,因此int foo::* ptr
指向数组的第二个元素(foo::b[1]
)。
又一个编辑:我需要通过bar.*ptr=2
访问数组中的元素,因为指针在其他地方被使用,因此无法使用{{1}调用它}或bar.*ptr[1]=2
。
答案 0 :(得分:5)
然而,编译器只是抱怨“无效使用非静态数据成员'foo :: b'”
这是因为foo::a
和foo::b
有不同的类型。更具体地说,foo::b
是int
s的大小为2的数组。你的指针声明必须兼容,即:
int (foo::*aptr)[2]=&foo::b;
是否可以这样做(或者至少没有工会)?
是的,见下文:
struct foo
{
int a;
int b[2];
};
int main()
{
foo bar;
int (foo::*aptr)[2]=&foo::b;
/* this is a plain int pointer */
int *bptr=&((bar.*aptr)[1]);
bar.a=1;
bar.b[0] = 2;
bar.b[1] = 11;
std::cout << (bar.*aptr)[1] << std::endl;
std::cout << *bptr << std::endl;
}
根据OP的要求更新了帖子。
答案 1 :(得分:3)
问题是,访问数组中的项是访问普通int的另一个间接级别。如果该数组是指针而不是您希望能够通过成员指针访问int。
struct foo
{
int a;
int *b;
};
int main()
{
foo bar;
int foo::* aptr=&(*foo::b); // You can't do this either!
bar.a=1;
std::cout << bar.*aptr << std::endl;
}
您可以做的是定义返回所需int的成员函数:
struct foo
{
int a;
int *b;
int c[2];
int &GetA() { return a; } // changed to return references so you can modify the values
int &Getb() { return *b; }
template <int index>
int &GetC() { return c[index]; }
};
typedef long &(Test::*IntAccessor)();
void SetValue(foo &f, IntAccessor ptr, int newValue)
{
cout << "Value before: " << f.*ptr();
f.*ptr() = newValue;
cout << "Value after: " << f.*ptr();
}
int main()
{
IntAccessor aptr=&foo::GetA;
IntAccessor bptr=&foo::GetB;
IntAccessor cptr=&foo::GetC<1>;
int local;
foo bar;
bar.a=1;
bar.b = &local;
bar.c[1] = 2;
SetValue(bar, aptr, 2);
SetValue(bar, bptr, 3);
SetValue(bar, cptr, 4);
SetValue(bar, &foo::GetC<0>, 5);
}
然后你至少有一个一致的界面,允许你在foo上改变不同的值。
答案 2 :(得分:1)
你不能用语言本身做到这一点。但你可以提升。将一个仿函数绑定到该数组的某个元素并将其分配给boost::function
:
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/function.hpp>
#include <iostream>
struct test {
int array[3];
};
int main() {
namespace lmb = boost::lambda;
// create functor that returns test::array[1]
boost::function<int&(test&)> f;
f = lmb::bind(&test::array, lmb::_1)[1];
test t = {{ 11, 22, 33 }};
std::cout << f(t) << std::endl; // 22
f(t) = 44;
std::cout << t.array[1] << std::endl; // 44
}
答案 3 :(得分:1)
2020年更新,带有实际解决方案:
首先,成员指针通常被实现为“只是偏移量”,尽管这很可怕。让我们看一个例子(在g ++ 9上,arch amd64):
struct S { int a; float b[10]; };
float(S::*mptr)[10] = &S::b;
*reinterpret_cast<uintptr_t *>(&mptr) //this is 4
int S::*iptr = &S::a;
*reinterpret_cast<uintptr_t *>(&iptr) //this is 0
iptr = nullptr;
*reinterpret_cast<uintptr_t *>(&iptr) //this seems to be 18446744073709551615 on my box
相反,您可以做一些包装(虽然很长,但是我不想删除便捷运算符):
#include <type_traits>
template<class M, typename T>
class member_ptr
{
size_t off_;
public:
member_ptr() : off_(0) {}
member_ptr(size_t offset) : off_(offset) {}
/* member access */
friend const T& operator->*(const M* a, const member_ptr<M, T>& p)
{ return (*a)->*p; }
friend T& operator->*(M* a, const member_ptr<M, T>& p)
{ return (*a)->*p; }
/* operator.* cannot be overloaded, so just take the arrow again */
friend const T& operator->*(const M& a, const member_ptr<M, T>& p)
{ return *reinterpret_cast<const T*>(reinterpret_cast<const char*>(&a) + p.off_); }
friend T& operator->*(M& a, const member_ptr<M, T>& p)
{ return *reinterpret_cast<T*>(reinterpret_cast<char*>(&a) + p.off_); }
/* convert array access to array element access */
member_ptr<M, typename std::remove_extent<T>::type> operator*() const
{ return member_ptr<M, typename std::remove_extent<T>::type>(off_); }
/* the same with offset right away */
member_ptr<M, typename std::remove_extent<T>::type> operator[](size_t offset) const
{ return member_ptr<M, typename std::remove_extent<T>::type>(off_)+offset; }
/* some operators */
member_ptr& operator++()
{ off_ += sizeof(T); return *this; };
member_ptr& operator--()
{ off_ -= sizeof(T); return *this; };
member_ptr operator++(int)
{ member_ptr copy; off_ += sizeof(T); return copy; };
member_ptr operator--(int)
{ member_ptr copy; off_ -= sizeof(T); return copy; };
member_ptr& operator+=(size_t offset)
{ off_ += offset * sizeof(T); return *this; }
member_ptr& operator-=(size_t offset)
{ off_ -= offset * sizeof(T); return *this; }
member_ptr operator+(size_t offset) const
{ auto copy = *this; copy += offset; return copy; }
member_ptr operator-(size_t offset) const
{ auto copy = *this; copy -= offset; return copy; }
size_t offset() const { return off_; }
};
template<class M, typename T>
member_ptr<M, T> make_member_ptr(T M::*a)
{ return member_ptr<M, T>(reinterpret_cast<uintptr_t>(&(((M*)nullptr)->*a)));}
现在我们可以直接将指针指向数组元素:
auto mp = make_member_ptr(&S::b)[2];
S s;
s->*mp = 123.4;
// s.b[2] is now expectably 123.4
最后,如果您真的非常喜欢物化引用,则可能会有点草率,并使它们组成:
// in class member_ptr, note transitivity of types M -> T -> TT:
template<class TT>
member_ptr<M,TT> operator+(const member_ptr<T,TT>&t)
{ return member_ptr<M,TT>(off_ + t.offset()); }
// test:
struct A { int a; };
struct B { A arr[10]; };
B x;
auto p = make_member_ptr(&B::arr)[5] + make_member_ptr(&A::a)
x->*p = 432.1;
// x.arr[5].a is now expectably 432.1
答案 4 :(得分:0)
typedef int (foo::*b_member_ptr)[2];
b_member_ptr c= &foo::b;
一切正常。
成员和函数指针用法的小技巧 试着写
char c = &foo::b; // or any other function or member pointer
并且在compiller错误中,您会看到预期的类型,对于您的案例int (foo::*)[2]
。
修改强>
如果没有这个指针,我不确定你想要的是合法的。为了向指针添加1个偏移量,您应该从成员数组上的指针获取数组上的指针。但是如果没有这个,你可以取消引用成员指针。
答案 5 :(得分:0)
我不确定这是否适合你,但我想做类似的事情并通过从另一个方向解决问题来解决这个问题。在我的班级中,我有几个对象,我想通过命名标识符访问或循环迭代。我没有创建指向数组中某些对象的成员指针,而是单独声明了所有对象,并创建了一个静态的成员指针数组。
像这样:
struct obj
{
int somestuff;
double someotherstuff;
};
class foo
{
public:
obj apples;
obj bananas;
obj oranges;
static obj foo::* fruit[3];
void bar();
};
obj foo::* foo::fruit[3] = { &foo::apples, &foo::bananas, &foo::oranges };
void foo::bar()
{
apples.somestuff = 0;
(this->*(fruit[0])).somestuff = 5;
if( apples.somestuff != 5 )
{
// fail!
}
else
{
// success!
}
}
int main()
{
foo blee;
blee.bar();
return 0;
}
这似乎对我有用。我希望有所帮助。