#include <iostream>
using namespace std;
class A
{
public:
A() : x(0) {}
// notice: not identical to const version but does update
void FA() {std::cout << "A" << std::endl; x++;}
void FA() const {std::cout << "const A" << std::endl;}
private:
int x;
};
class B
{
public:
B() : x(0) {}
// notice: not identical to const version but does update
void FB() {std::cout << "B" << std::endl; x++;}
void FB() const {std::cout << "const B" << std::endl;}
private:
int x;
};
class C
{
public:
void FC()
{
bool condition = true; // should be set to a real condition
if(condition)
{
a.FA();
}
b.FB();
}
void FC() const
{
bool condition = true; // should be set to a real condition
if(condition)
{
a.FA();
}
b.FB();
}
private:
A a;
B b;
};
int main() {
C c;
c.FC();
const C cc;
cc.FC();
return 0;
}
首先,抱歉这个冗长的标题。 如何在函数 FC , FC const 中避免C类中的代码重复?鉴于您不能使用将此转换为 const 并从非const FC版本调用const FC版本的技巧,因为非const FC的实体将调用将执行更新的函数与其对应的常量不同。
答案 0 :(得分:7)
让模板成员函数执行实际工作。换句话说:试试这个:
class C
{
public:
void FC()
{
FC_Impl( *this );
}
void FC() const
{
FC_Impl( *this );
}
private:
template <typename Self>
static void FC_Impl( Self & self )
{
bool condition = true; // should be set to a real condition
if(condition)
{
self.a.FA();
}
self.b.FB();
}
A a;
B b;
};
答案 1 :(得分:0)
拉尔夫给出了很好的答案。我认为值得一提的是,提供具有相同名称但具有不同参数类型的自由函数,我们允许自己在高级别表达意图,而自由函数充当适配器。我们允许ADL为我们找到正确的函数重载(或特化)。
通过这种方式,我们不需要知道成员函数的名称以表达逻辑。在这个例子中,它会使类C
更容易修改和演化:
#include <iostream>
#include <utility>
using namespace std;
// general case
template<class T>
decltype(auto) apply_F(T&& t)
{
return t.F();
}
// call apply_F with either an X or a Y and return the result )can be void)
template<class X, class Y>
auto conditionally_apply_F(bool condition, X&& x, Y&& y)
-> std::common_type_t<decltype(apply_F(x)), decltype(apply_F(y))>
{
if (condition) {
return apply_F(x);
}
else {
return apply_F(y);
}
}
// provides F member function - no need for specific adapter
class A
{
public:
A() : x(0) {}
// notice: not identical to const version but does update
void F() {std::cout << "A" << std::endl; x++;}
void F() const {std::cout << "const A" << std::endl;}
private:
int x;
};
// has differing names implementing the concept of F - so we'll need an adapter
class B
{
public:
B() : x(0) {}
// notice: not identical to const version but does update
void F_mutable() {std::cout << "B" << std::endl; x++;}
void F_const() const {std::cout << "const B" << std::endl;}
private:
int x;
};
// adapter overloads
decltype(auto) apply_F(B const& t)
{
return t.F_const();
}
decltype(auto) apply_F(B& t)
{
return t.F_mutable();
}
// class C current expressed in terms of A and B, but no longer tied to these types
class C
{
public:
void FC()
{
bool condition = true; // should be set to a real condition
conditionally_apply_F(condition, a, b);
}
void FC() const
{
bool condition = true; // should be set to a real condition
conditionally_apply_F(condition, a, b);
}
private:
A a;
B b;
};
int main() {
C c;
c.FC();
const C cc;
cc.FC();
return 0;
}