Здесь есть одна возможность. Некоторые из предположений в комментариях. Конечно, есть и другие способы сделать это. Размер набора в знаменателе второй формулы можно сделать проще, чем длину набора или списка, но мой способ избегает использования памяти для набора / списка и более согласуется с числителем.
def formula1(X, n, a, b):
"""Return the first formula for matrix X, size n, and indices a and b.
"""
return sum(X[a][t] - X[b][t] for t in range(1, n+1)) / n
def formula2(X, n, i, j, x, y, a, P):
"""Return the second formula for matrix X, size n, indices i, j, x, and y,
array or mapping a, array or mapping of sets P.
"""
numer = sum(abs(X[i][t] - X[j][t])
for t in range(1, n+1)
if a[t] in P[x] or a[t] in P[y])
denom = sum(1
for t in range(1, n+1)
if a[t] in P[x] or a[t] in P[y])
return numer / denom
Это - "указатель на участника" - следующий код иллюстрирует свое использование:
#include <iostream>
using namespace std;
class Car
{
public:
int speed;
};
int main()
{
int Car::*pSpeed = &Car::speed;
Car c1;
c1.speed = 1; // direct access
cout << "speed is " << c1.speed << endl;
c1.*pSpeed = 2; // access via pointer to member
cout << "speed is " << c1.speed << endl;
return 0;
}
относительно , почему Вы хотели бы сделать это, хорошо это дает Вам другой уровень абстракции, который может решить некоторые хитрые проблемы. Но честно говоря, я никогда не должен был использовать их в своем собственном коде.
Редактирование: я не могу думать бесцеремонно об убедительном использовании для указателей на членские данные. Указатель на функции членства может использоваться в сменной архитектуре, но еще раз создание примера в небольшом пространстве побеждает меня. Следующее является моей лучшей (непротестированной) попыткой - Применять функция, которая сделала бы некоторых пред & сообщение, обрабатывающее прежде, чем применить выбранную пользователями функцию членства к объекту:
void Apply( SomeClass * c, void (SomeClass::*func)() ) {
// do hefty pre-call processing
(c->*func)(); // call user specified function
// do hefty post-call processing
}
круглые скобки приблизительно c->*func
необходимы, потому что ->*
оператор имеет более низкий приоритет, чем оператор вызова функции.
Я думаю, что Вы только хотели бы сделать это, если бы членские данные были довольно большими (например, объект другого довольно значительного класса), и у Вас есть некоторая внешняя подпрограмма, которая только работает над ссылками на объекты того класса. Вы не хотите копировать членский объект, таким образом, это позволяет Вам раздать его.
Можно использовать массив указателя на (гомогенные) членские данные для включения двойного, именованный участник (т.е. x.data) и нижний индекс массива (т.е. x [idx]) интерфейс.
#include <cassert>
#include <cstddef>
struct vector3 {
float x;
float y;
float z;
float& operator[](std::size_t idx) {
static float vector3::*component[3] = {
&vector3::x, &vector3::y, &vector3::z
};
return this->*component[idx];
}
};
int main()
{
vector3 v = { 0.0f, 1.0f, 2.0f };
assert(&v[0] == &v.x);
assert(&v[1] == &v.y);
assert(&v[2] == &v.z);
for (std::size_t i = 0; i < 3; ++i) {
v[i] += 1.0f;
}
assert(v.x == 1.0f);
assert(v.y == 2.0f);
assert(v.z == 3.0f);
return 0;
}
Одним путем я использовал его, то, если у меня есть две реализации того, как сделать что-то в классе, и я хочу выбрать один во времени выполнения, не имея необходимость постоянно проходить, если оператор т.е.
class Algorithm
{
public:
Algorithm() : m_impFn( &Algorithm::implementationA ) {}
void frequentlyCalled()
{
// Avoid if ( using A ) else if ( using B ) type of thing
(this->*m_impFn)();
}
private:
void implementationA() { /*...*/ }
void implementationB() { /*...*/ }
typedef void ( Algorithm::*IMP_FN ) ();
IMP_FN m_impFn;
};
, Очевидно, это только практически полезно, если Вы чувствуете, что код куется достаточно, что, если оператор замедляет вещи, сделанные, например, глубокие в кишках некоторого интенсивного алгоритма где-нибудь. Я все еще думаю, что это более изящно, чем, если оператор даже в ситуациях, где это не имеет никакого практического применения, но это - просто мой opnion.
IBM имеет еще некоторую документацию относительно того, как использовать это. Кратко, Вы используете указатель в качестве смещения в класс. Вы не можете использовать эти указатели кроме класса, который они отсылают к, таким образом:
int Car::*pSpeed = &Car::speed;
Car mycar;
mycar.*pSpeed = 65;
Это кажется немногим неясным, но одно возможное приложение - то, при попытке написать код для десериализации универсальных данных во многие различные типы объектов, и Ваш код должен обработать типы объектов, о которых это абсолютно ничего не знает (например, Ваш код находится в библиотеке, и объекты, в которые Вы десериализовываете, были созданы пользователем Вашей библиотеки). Членские указатели дают Вам, универсальный, получеткий способ относиться к отдельным смещениям элемента данных, не имея необходимость обращаться к пустоте без типов * обманывает способ, которым Вы могли бы для структур C.
Можно позже получить доступ к этому участнику, на любой экземпляр:
int main()
{
int Car::*pSpeed = &Car::speed;
Car myCar;
Car yourCar;
int mySpeed = myCar.*pSpeed;
int yourSpeed = yourCar.*pSpeed;
assert(mySpeed > yourSpeed); // ;-)
return 0;
}
Примечание, что Вам действительно нужен экземпляр для обращения к нему, таким образом, это не работает как делегат.
Это редко используется, мне был нужен он, возможно, несколько раз во всех моих годах.
Обычно использование интерфейса (т.е. чистый базовый класс в C++) является лучшим проектным решением.
Другое приложение является навязчивыми списками. Тип элемента может сказать список, каковы его следующие/предыдущие указатели. Таким образом, список не использует трудно кодированные имена, но может все еще использовать существующие указатели:
// say this is some existing structure. And we want to use
// a list. We can tell it that the next pointer
// is apple::next.
struct apple {
int data;
apple * next;
};
// simple example of a minimal intrusive list. Could specify the
// member pointer as template argument too, if we wanted:
// template<typename E, E *E::*next_ptr>
template<typename E>
struct List {
List(E *E::*next_ptr):head(0), next_ptr(next_ptr) { }
void add(E &e) {
// access its next pointer by the member pointer
e.*next_ptr = head;
head = &e;
}
E * head;
E *E::*next_ptr;
};
int main() {
List<apple> lst(&apple::next);
apple a;
lst.add(a);
}
Это позволяет связать членские переменные и функции универсальным способом. Следующее является примером с Вашим Автомобильным классом. Более общее использование связало бы std::pair::first
и ::second
при использовании в алгоритмах STL и Повышении на карте.
#include <list>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
class Car {
public:
Car(int s): speed(s) {}
void drive() {
std::cout << "Driving at " << speed << " km/h" << std::endl;
}
int speed;
};
int main() {
using namespace std;
using namespace boost::lambda;
list<Car> l;
l.push_back(Car(10));
l.push_back(Car(140));
l.push_back(Car(130));
l.push_back(Car(60));
// Speeding cars
list<Car> s;
// Binding a value to a member variable.
// Find all cars with speed over 60 km/h.
remove_copy_if(l.begin(), l.end(),
back_inserter(s),
bind(&Car::speed, _1) <= 60);
// Binding a value to a member function.
// Call a function on each car.
for_each(s.begin(), s.end(), bind(&Car::drive, _1));
return 0;
}