Reputation: 57870
I have a C++ class with two overloads of a private method, and those should be connected to two overloads of a public method.
The public method is the same in both overloads, it differs only in which overload of the private method it calls. The two private method overloads, on the other hand, are entirely different, which is why I chose to overload them in the first place.
To avoid duplicating code in the public method, this seems like a good use case for perfect forwarding. But on the other hand, then if you want to call the public method and are not familiar with the API, it's difficult to see which arguments you have to provide; you would have to examine the body of the public method, and then consult the private interface to see which overloads of the private method exist.
I've tried to make a toy class that illustrates my problem:
class Foo {
public:
struct DontCopyTheBaz {};
private:
bool init_from_baz(Baz& a_baz);
bool init_from_baz(Baz& a_baz, DontCopyTheBaz);
public:
// ...should I use perfect forwarding, making the API not easily readable?
template<typename... Args>
static Foo* new_for_baz(Baz& a_baz, Args&&... args) {
Foo* the_foo = new Foo();
if (!the_foo->init_from_baz(a_baz, std::forward<Args>(args)...)) {
delete the_foo;
return nullptr;
}
return the_foo;
}
// ...or should I write duplicated code?
static Foo* new_for_baz(Baz& a_baz) {
Foo* the_foo = new Foo();
if (!the_foo->init_from_baz(a_baz)) {
delete the_foo;
return nullptr;
}
return the_foo;
}
static Foo* new_for_baz(Baz& a_baz, DontCopyTheBaz no_copy) {
Foo* the_foo = new Foo();
if (!the_foo->init_from_baz(a_baz, no_copy)) {
delete the_foo;
return nullptr;
}
return the_foo;
}
};
(In reality both the private and public methods are longer and more complicated.)
Is there a way to avoid the code duplication, while still making the API easy to understand?
Upvotes: 0
Views: 101
Reputation: 217275
You can add extra indirection to factorize the code and have clean interface:
class Foo {
public:
struct DontCopyTheBaz {};
private:
bool init_from_baz(Baz& a_baz);
bool init_from_baz(Baz& a_baz, DontCopyTheBaz);
template<typename... Args>
static std::unique_ptr<Foo> new_for_baz_impl(Baz& a_baz, Args&&... args) {
auto the_foo = std::make_unique<Foo>();
if (!the_foo->init_from_baz(a_baz, std::forward<Args>(args)...)) {
return nullptr;
}
return the_foo;
}
public:
static std::unique_ptr<Foo> new_for_baz(Baz& a_baz) {
return new_for_baz_impl(a_baz);
}
static std::unique_ptr<Foo> new_for_baz(Baz& a_baz, DontCopyTheBaz no_copy) {
return new_for_baz_impl(a_baz, no_copy);
}
};
Upvotes: 2