Сегодня я написал некоторый код, который должен был добавлять элементы в различные переменные контейнера в зависимости от типа параметра шаблона. Я решил это, написав вспомогательный класс друга, специализирующийся на собственном параметре шаблона, который имел переменную-член исходного класса. Это спасло меня от нескольких сотен строк повторения, не добавляя много сложностей. Тем не менее, это казалось клуджем. Я хотел бы знать, есть ли лучший, более элегантный способ.
Приведенный ниже код является сильно упрощенным примером, иллюстрирующим проблему и мое решение. Компилируется в g ++.
#include <vector>
#include <algorithm>
#include <iostream>
namespace myNS{
template<class Elt>
struct Container{
std::vector<Elt> contents;
template<class Iter>
void set(Iter begin, Iter end){
contents.erase(contents.begin(), contents.end());
std::copy(begin, end, back_inserter(contents));
}
};
struct User;
namespace WkNS{
template<class Elt>
struct Worker{
User& u;
Worker(User& u):u(u){}
template<class Iter>
void set(Iter begin, Iter end);
};
};
struct F{ int x; explicit F(int x):x(x){} };
struct G{ double x; explicit G(double x):x(x){} };
struct User{
Container<F> a;
Container<G> b;
template<class Elt>
void doIt(Elt x, Elt y){
std::vector<Elt> v; v.push_back(x); v.push_back(y);
Worker<Elt>(*this).set(v.begin(), v.end());
}
};
namespace WkNS{
template<class Elt> template<class Iter>
void Worker<Elt>::set(Iter begin, Iter end){
std::cout << "Set a." << std::endl;
u.a.set(begin, end);
}
template<> template<class Iter>
void Worker<G>::set(Iter begin, Iter end){
std::cout << "Set b." << std::endl;
u.b.set(begin, end);
}
};
};
int main(){
using myNS::F; using myNS::G;
myNS::User u;
u.doIt(F(1),F(2));
u.doIt(G(3),G(4));
}
User
- это класс, который я писал.
Worker
мой класс помощника. У меня есть это в его собственном пространстве имен, потому что я не хочу, чтобы это вызывало проблемы вне myNS.
Container
- это контейнерный класс, определение которого я не хочу изменять, но используется User
в своих переменных экземпляра.
doIt<F>
должен изменить a. doIt<G>
должен изменить б.
F
и G
открыты для ограниченной модификации, если это приведет к более элегантному решению. (Как пример одной такой модификации, в реальном приложении конструктор F
принимает фиктивный параметр, чтобы он выглядел как конструктор G
и избавил меня от повторения.)
В реальном коде Worker
является другом User
, а переменные-члены являются закрытыми. Чтобы сделать пример проще для написания, я сделал все публичным. Однако решение, которое требует публичности, на самом деле не отвечает на мой вопрос.
Учитывая все эти предостережения, есть ли лучший способ написать User::doIt
?