Duplicate code using C ++ 11

I am currently working on a project and I have the following problem.

I have a C ++ method that I want to work in two different ways:

void MyFunction() { foo(); bar(); foobar(); } void MyFunctionWithABonus() { foo(); bar(); doBonusStuff(); foobar(); } 

And I would like not to duplicate my code, because the actual function is much longer. The problem is that under no circumstances should I add program runtime when MyFunction is called instead of MyFunctionWithABonus. That is why I cannot just have a boolean parameter that I am checking with C ++ comparison.

My idea would be to use C ++ templates to practically duplicate my code, but I can't think of a way to do that I don't have extra runtime in and I don't need to duplicate the code.

I am not an expert with templates, so I can skip something.

Do you have any idea? Or is it just not possible in C ++ 11?

+80
c ++ c ++ 11 templates
Apr 25 '17 at 8:18
source share
6 answers

With pattern and lambda you can:

 template <typename F> void common(F f) { foo(); bar(); f(); foobar(); } void MyFunction() { common([](){}); } void MyFunctionWithABonus() { common(&doBonusStuff); } 

otherwise you can just create the prefix and suffix function.

 void prefix() { foo(); bar(); } void suffix() { foobar(); } void MyFunction() { prefix(); suffix(); } void MyFunctionWithABonus() { prefix(); doBonusStuff(); suffix(); } 
+55
Apr 25 '17 at 8:25
source share

Something like this would be nice:

 template<bool bonus = false> void MyFunction() { foo(); bar(); if (bonus) { doBonusStuff(); } foobar(); } 

Call through:

 MyFunction<true>(); MyFunction<false>(); MyFunction(); // Call myFunction with the false template by default 

An ugly template can be avoided by adding some useful wrappers to functions:

 void MyFunctionAlone() { MyFunction<false>(); } void MyFunctionBonus() { MyFunction<true>(); } 

You can find some nice information about this method there . This is an "old" paper, but the technique itself remains absolutely true.

If you have access to a good C ++ 17 compiler, you can even promote this technique using constexpr if:

 template <int bonus> auto MyFunction() { foo(); bar(); if constexpr (bonus == 0) { doBonusStuff1(); } else if constexpr (bonus == 1) { doBonusStuff2(); } else if constexpr (bonus == 2) { doBonusStuff3(); } else if constexpr (bonus == 3) { doBonusStuff4(); } // Guarantee that this function will not compile // if a bonus different than 0,1,2,3 is passer else { static_assert(false);}, foorbar(); } 
+129
Apr 25 '17 at 8:35
source share

Given some comments made by the OP regarding debugging, here is the version that calls doBonusStuff() for debug builds, but does not release assemblies (which define NDEBUG ):

 #if defined(NDEBUG) #define DEBUG(x) #else #define DEBUG(x) x #endif void MyFunctionWithABonus() { foo(); bar(); DEBUG(doBonusStuff()); foobar(); } 

You can also use the assert macro if you want to check the condition and fail if it is false (but only for debug builds, release assemblies will not check).

Be careful if doBonusStuff() has side effects, as these side effects will not be present in release builds and may invalidate assumptions made in the code.

+27
Apr 25 '17 at 11:11
source share

Here is a small variation of Jarod42's answer using variable templates so that the caller can provide null or bonus features:

 void callBonus() {} template<typename F> void callBonus(F&& f) { f(); } template <typename ...F> void MyFunction(F&&... f) { foo(); bar(); callBonus(std::forward<F>(f)...); foobar(); } 

Call Code:

 MyFunction(); MyFunction(&doBonusStuff); 
+18
Apr 25 '17 at 10:24
source share

Another version using only templates and non-redirecting functions, as you said you don't want run-time overhead. Since I'm worried, this increases compilation time:

 #include <iostream> using namespace std; void foo() { cout << "foo\n"; }; void bar() { cout << "bar\n"; }; void bak() { cout << "bak\n"; }; template <bool = false> void bonus() {}; template <> void bonus<true>() { cout << "Doing bonus\n"; }; template <bool withBonus = false> void MyFunc() { foo(); bar(); bonus<withBonus>(); bak(); } int main(int argc, const char* argv[]) { MyFunc(); cout << "\n"; MyFunc<true>(); } output: foo bar bak foo bar Doing bonus bak 

Now there is only one version of MyFunc() with the bool parameter as a template argument.

+11
Apr 25 '17 at 8:40
source share

You can use tagging and a simple overload function:

 struct Tag_EnableBonus {}; struct Tag_DisableBonus {}; void doBonusStuff(Tag_DisableBonus) {} void doBonusStuff(Tag_EnableBonus) { //Do bonus stuff here } template<class Tag> MyFunction(Tag bonus_tag) { foo(); bar(); doBonusStuff(bonus_tag); foobar(); } 

It is easy to read / understand, it can be deployed without sweat (and without if templates) by adding more tags), and, of course, it will not leave a mark on the desktop.

The calling syntax is pretty friendly, but of course it can be wrapped in vanilla calls:

 void MyFunctionAlone() { MyFunction(Tag_DisableBonus{}); } void MyFunctionBonus() { MyFunction(Tag_EnableBonus{}); } 

Sending tags is a widely used universal programming technology, here is a good basics article.

+8
Apr 27 '17 at 10:09 on
source share



All Articles