Я на самом деле не предлагаю применять этот дизайн где угодно, но мне все же было любопытно, как можно было бы реализовать это в C ++, в частности, учитывая отсутствие отражения в C ++. (Я одновременно изучаю и экспериментирую с функциями C ++ 11, поэтому, пожалуйста, используйте функции C ++ 11 там, где это полезно.)
То, чего я хочу достичь, это почти чисто косметическое.
Мне бы хотелось, чтобы класс связывался с произвольным числом, скажем, векторов, используя ссылочные члены (которые, как я понимаю, должны быть инициализированы во время построения), но предоставляет «псевдонимы» для доступа к этим векторам в качестве членов.
Чтобы привести минимальный пример, я хочу, чтобы это работало
std::vector<int> one;
std::vector<int> two;
std::vector<int> three;
Foo foo(std::make_pair('B', one),
std::make_pair('D', two),
std::make_pair('F', three));
foo.DoSomething();
где
class Foo
{
public:
// I'm using variadic templates here for sake of learning,
// but initializer lists would work just as well.
template <typename ...Tail>
Foo(std::pair<char, std::vector<int>&> head, Tail&&... tail) // : ???
{
// ???
}
virtual void DoSomething()
{
D.push_back(42);
std::cout << D[0] << std::endl;
}
private:
std::vector<int> A&, B&, C&, D&, E&, F&, G&; // and so on...
}
а также чтобы
std::cout << one[0] << std::endl; // outputs 42 from outside the class...
Зачем кому-то это делать? Ну я не действительно хочу сделать это, но приложение, которое я имел в виду, было примерно таким. Предположим, я создаю какой-то инструмент для анализа данных, и у меня есть клиенты или операторы, которые знают базовую логику и синтаксис C ++, но не понимают ООП или что-то еще, кроме CS 101. Если бы они могли писать, все было бы намного проще. их собственный DoSomething()
S на лету, а не сообщать все потребности разработчиков. Однако заставить их настроить учетные записи UNIX, научить их компилировать и т. Д. Нереально. Итак, предположим, что вместо этого я хотел бы создать интранет-веб-интерфейс, который позволит им написать текст DoSomething()
и настройте, какие наборы данных они хотели бы «псевдоним» в верхнем регистре char
и после отправки генерирует C ++ для дочернего класса Foo
что переопределяет DoSomething()
, затем создает, запускает и возвращает вывод. (Подозрительно специфично для «гипотетического», а? 🙂 Хорошо, что-то вроде этой ситуации действительно существует в моем мире — однако это только вдохновило эту идею и желание исследовать ее — я не думаю, что это стоило бы на самом деле реализации.) Очевидно, весь этот верхний регистр char
испытание не является абсолютно необходимым, но это было бы приятно, потому что наборы данных уже связаны со стандартными буквами, например P для цены, Q для количества и т. Д.
Если честно, я не могу понять, как бы я сделал эту работу, используя ссылки. я предпочитать используя ссылки, если это возможно, для эти причины.
Думаю, с указателями я бы сделал это …
class Foo
{
public:
template <typename ...Tail>
Foo(std::pair<char, std::vector<int>*> head, Tail&&... tail)
{
std::vector<int>[26] vectors = {A, B, C, D, E, F, G}; // and so on...
// I haven't learned how to use std::forward yet, but you get the picture...
// And dear lord, forgive me for what I'm about to do...
vectors[tail.first - 65] = tail.second;
}
virtual void DoSomething()
{
D->push_back(42);
std::cout << (*D)[0] << std::endl;
}
private:
std::vector<int> A*, B*, C*, D*, E*, F*, G*; // and so on...
}
Но даже это не так уж и элегантно.
Есть ли способ использовать ссылки и добиться этого?
Есть ли способ сделать это более общим, например использовать методы псевдоотражения, чтобы избежать необходимости перечислять все заглавные буквы снова?
Какие-нибудь предложения об альтернативных проектах, которые сохранили бы основную цель (косметический псевдоним, который я описал) более элегантным или компактным способом?
Вы можете использовать что-то вроде:
class Foo
{
public:
template <typename ...Ts>
Foo(Ts&&... ts) : m({std::forward<Ts>(ts)...}),
A(m.at('A')),
B(m.at('B'))
// and so on...
{
}
virtual void DoSomething()
{
A.push_back(42);
std::cout << A[0] << std::endl;
}
private:
std::map<char, std::vector<int>&> m;
std::vector<int> &A, &B; //, &C, &D, &E, &F, &G; // and so on...
};
но это требует, чтобы каждый вектор был задан, так
Foo(std::vector<int> (&v)[26]) : A(v[0]), B(v[1]) // and so on...
{
}
или же
Foo(std::vector<int> &a, std::vector<int> &b /* And so on */) : A(a), B(b) // and so on...
{
}
кажется более подходящим.
И это кажется еще проще, если это класс Foo
который владеет vector
так что у вас будет просто
class Foo
{
public:
virtual ~Foo() {}
virtual void DoSomething() { /* Your code */ }
std::vector<int>& getA() { return A; }
private:
std::vector<int> A, B, C, D; // And so on
};
и предоставить геттеры для инициализации внутренних векторов.
а потом
std::vector<int>& one = foo.GetA(); // or foo.A if you let the members public.