我正在编写一段代码,将“Person”对象从一个数据表示复制到另一个数据表示。每个类中的名称(名称,地址,标题)匹配,所有类型都是字符串。对于每个字段,我想根据某些条件应用相同的转换,这些条件也取决于字段名称。棘手的部分是重复代码使用基于字段名称的函数后缀。它看起来像这样:
LibraryA::Person person1;
LibraryB::Person person2;
if (person1.name_valid() && [...somestuff...]) {
string *v = SomeOtherFunction(person.name())
person2.set_name(v);
}
if (person1.address_valid() && [...somestuff...]) {
string *v = SomeOtherFunction(person.address())
person2.set_address(v);
}
if (person1.title_valid() && [...somestuff...]) {
string *v = SomeOtherFunction(person.title())
person2.set_title(v);
}
是否有技巧(或技术:))将重复部分分解为模板?我更喜欢不涉及定义宏的解决方案(这太容易了:))
答案 0 :(得分:1)
您可以使用指向成员函数的指针。例如(我没有检查此代码是否编译):
typedef bool (LibraryA::Person::Validator)();
typedef string (LibraryA::Person::FieldGetter)();
typedef void (LibraryB::Person::FieldSetter)(string*);
void ApplyField(LibraryA::Person& person1, LibraryB::Person& person2, Validator vl, FieldGetter get, FieldSetter set)
{
if (person1.vl() && [...somestuff...])
{
string* v = SomeOtherFunction(person1.get());
person2.set(v);
}
}
ApplyField(person1, person2, &LibraryA::Person::name_valid, &LibraryA::Person::name, &LibraryB::Person::set_name);
ApplyField(person1, person2, &LibraryA::Person::address_valid, &LibraryA::Person::address, &LibraryB::Person::set_address);
ApplyField(person1, person2, &LibraryA::Person::title_valid, &LibraryA::Person::title, &LibraryB::Person::set_title);
我不认为模板适合这里,因为所有字段都是相同的类型。 在这种情况下,我真的不知道你对宏的反应是什么。如果需要,可以使用macrot生成对ApplyField()的调用。
答案 1 :(得分:1)
这符合您的要求,但我是否会使用它是一个不同的问题。只有当巨大重复量时,我才会通过这条路径,然后我会将它与宏结合起来以简化调用代码:
void test_and_set( Person const & person1, Person & person2,
bool (Person::*test)() const,
std::string (Person::*get)() const,
void (Person::*set)( std::string const &) )
{
if ( (person1.*test)() ) {
(person2.*set)( (person1.*get)() );
}
}
用作:
test_and_set( person1, person2, &Person::valid_name, &Person::get_name, &Person::set_name );
并结合当地宏观:
#define TEST_AND_SET( p1, p2, field ) \
test_and_set( (p1), (p2), &Person::valid_##field, &Person::get_##field, &Person::set_##field )
TEST_AND_SET( person1, person2, name );
TEST_AND_SET( person1, person2, title );
#undef TEST_AND_SET
答案 2 :(得分:1)
这个快速,肯定不是有效的C ++,但我希望你明白这个想法:
struct MyFunctor
{
Person *person1, *person2;
void operator()(void Person::*validator(), string* Person::*getter(), void Person::*setter(string *))
{
if (person1->*validator() && [...somestuff...])
{
string* v = SomeOtherFunction(person1->*getter());
person2->*setter(v);
}
}
};
// Usage
MyFunctor f = { person1, person2 };
f(&Person::name_valid, &Person::name, &Person::set_name);
f(&Person::address_valid, &Person::address, &Person::set_address);
f(&Person::title_valid, &Person::title, &Person::set_title);
答案 3 :(得分:1)
您可以使用指向成员对象的数组,将其填充转换的源和目标,然后将转换应用于该数组中的每个条目。这看起来像这样:
struct trans_info {
trans_info(bool (S::*valid)() const,
std::string* (S::*get)()const,
void (T::*set)(std::string*)):
valid_(valid),
get_(get),
set_(set)
{
}
bool (S::*valid_)() const;
std::string* (S::*get_)() const;
void (S::*set_)(std::string*);
};
trans_info const info[] = {
trans_info(&S::name_valid, &S::name, &T::set_name),
trans_info(&S::address_valid, &S::address, &T::set_address),
trans_info(&S::title_valid, &S::title, &T::set_title),
...
};
template <typename T, int Size> T* begin(T (&array)[Size]) { return array; }
template <typename T, int Size> T* end(T (&array)[Size]) { return array + Size; }
transform(S const& person1, T& person2)
{
for (trans_info const* it(begin(info)), e(end(info)); it != end; ++it)
{
if ((person1.*(it->valid_))() && [...somestuff...]) {
string *v = SomeOtherFunction(person1.*(it->get_))())
(person2.*(it->set))(v);
}
}
}
答案 4 :(得分:0)
如果人物对象不可变,那你就不走运了。
如果不是,请使用标记类Person::Name
,Person::Address
等将信息排除在方法名称之外,然后重写*_valid
和{{1}使用函数重载:
*_set
答案 5 :(得分:0)
您可以将指针到成员的参数用于模板。
但是我质疑使用指向字符串的指针,这看起来像是一个可能的内存泄漏。