C++ 最小化C+中的重复代码+;,一个不那么直截了当的案例
我正在编写一段代码,将“Person”对象从一个数据表示形式复制到另一个数据表示形式。每个类中的名称(名称、地址、标题)匹配,所有类型都是字符串。对于每个字段,我希望根据一些同样依赖于字段名的条件应用相同的转换。棘手的是,重复代码使用基于字段名的函数后缀。它看起来像这样:C++ 最小化C+中的重复代码+;,一个不那么直截了当的案例,c++,dry,C++,Dry,我正在编写一段代码,将“Person”对象从一个数据表示形式复制到另一个数据表示形式。每个类中的名称(名称、地址、标题)匹配,所有类型都是字符串。对于每个字段,我希望根据一些同样依赖于字段名的条件应用相同的转换。棘手的是,重复代码使用基于字段名的函数后缀。它看起来像这样: LibraryA::Person person1; LibraryB::Person person2; if (person1.name_valid() && [...somestuff...]) {
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);
}
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);
}
}
}
是否有技巧(或技巧:)将重复部分分解成模板?我更喜欢不涉及定义宏的解决方案(这太容易了:)如果person对象对您来说是不可变的,那么您就倒霉了 如果不是,请使用标记类
Person::name
,Person::Address
等将信息从方法名称中剔除,然后重新写入*\u valid
和*\u set
以使用函数重载:
bool Person::is_valid( Name, std::string ) {...)
bool Person::is_valid( Address, std::string ) {...)
如果person对象对您来说是不可变的,那么您就不走运了 如果不是,请使用标记类
Person::name
,Person::Address
等将信息从方法名称中剔除,然后重新写入*\u valid
和*\u set
以使用函数重载:
bool Person::is_valid( Name, std::string ) {...)
bool Person::is_valid( Address, std::string ) {...)
可以使用指向模板的成员参数的指针
但我质疑字符串指针的使用,这看起来像是内存泄漏。您可以使用指向模板成员参数的指针
但我对使用指向字符串的指针表示怀疑,这看起来可能是内存泄漏。您可以使用指向成员函数的指针。例如(我没有检查此代码是否编译): 我认为模板不适合这里,因为所有字段的类型都相同。
我真的不知道在这种情况下你对宏有什么看法。如果需要,可以使用宏来生成对ApplyField()的调用。可以使用指向成员函数的指针。例如(我没有检查此代码是否编译): 我认为模板不适合这里,因为所有字段的类型都相同。
我真的不知道在这种情况下你对宏有什么看法。如果需要,可以使用宏来生成对ApplyField()的调用。这符合您的要求,但我是否使用它是另一个问题。只有在有大量重复的情况下,我才会通过此路径,然后将其与宏结合,以简化调用代码:
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
这符合你的要求,但我是否会使用它是一个不同的问题。只有在有大量重复的情况下,我才会通过此路径,然后将其与宏结合,以简化调用代码:
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
这是快速的,当然不是有效的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);
这是快速的,当然不是有效的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);
您可以使用指向成员对象的指针数组,将其填充为转换的源和目标,然后将转换应用于该数组中的每个条目。这可能看起来像这样:
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);
}
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);
}
}
}
struct trans\u info{
传输信息(bool(S::*有效)常数,
std::string*(S::*get)()const,
void(T::*set)(标准::字符串*):
有效(有效),,
得到(得到),,
集合(集合)
{
}
bool(S):*有效)(const ;;
std::string*(S::*get_u1;)const;
空(S::*set_)(标准::字符串*);
};
传输信息常量信息[]={
传输信息(&S::名称有效,&S::名称,&T::设置名称),
传输信息(&S::地址有效,&S::地址,&T::设置地址),
trans_信息(&S::title_有效,&S::title,&T::set_title),
...
};
模板T*begin(T(&array)[Size]){return array;}
模板T*end(T(&array)[Size]){return array+Size;}
变换(S常量和person1、T和person2)
{
for(trans_info const*it(begin(info)),e(end(info));it!=end;+it)
{
如果((person1.*(it->valid_))()&&[…somestuff…]){
string*v=SomeOtherFunction(person1.*(it->get_))())
(person2.*(it->set))(v);
}
}
}
您可以使用指向成员对象的指针数组,用转换的源和目标填充它,然后将转换应用于该数组中的每个条目。这可能看起来像这样:
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);
}
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);
}
}
}
struct trans\u info{
传输信息(bool(S::*有效)常数,
std::string*(S::*get)()const,
void(T::*set)(标准::字符串*):
有效(有效),,
得到(得到),,
集合(集合)
{
}
bool(S):*有效)(const ;;
std::string*(S::*get_u1;)const;
空(S::*set_)(标准::字符串*);
};
传输信息常量信息[]={
传输信息(&S::名称有效,&S::名称,&T::设置名称),
传输信息(&S::地址有效,&S::地址,&T::设置地址),
trans_信息(&S::title_有效,&S::title,&T::set_title),
...
};
模板T*begin(T(&array)[Size]){return array;}
模板T*end(T(&array)[Size]){return array+Size;}
变换(S常量和person1、T和person2)
{
for(trans_info const*it(begin(info)),e(end(info));it!=end;+it)
{
如果((person1.*(it->valid_))()&&[…somestuff…]){
string*v=SomeOtherFunction(person1.*(it->get_))())
(person2.*(it->set))(v);
}
}
}
至少您可以使用宏。在我所使用的更动态的语言中,我曾多次希望如此。对于每个if
语句,[…something…]
是否都相同?@gahooa在这些更动态的语言中,您经常可以在运行时基于变量调用方法,从而使这变得相当简单。如果只有3个字段,这与其说是重复,不如说是重复