使用C ++ 11重复的代码
我目前正在进行一个项目,我有以下问题。
我有一个C ++方法,我想以两种不同的方式工作:
void MyFunction() { foo(); bar(); foobar(); } void MyFunctionWithABonus() { foo(); bar(); doBonusStuff(); foobar(); }
而且我不想复制我的代码,因为实际的function更长。 问题是我不能在任何情况下调用MyFunction而不是MyFunctionWithABonus来为程序添加执行时间。 这就是为什么我不能只有一个布尔参数,我检查与C + +比较。
我的想法本来是使用C ++模板来虚拟复制我的代码,但我想不出一种做法,我没有额外的执行时间,我不必复制代码。
我不是模板的专家,所以我可能会错过一些东西。
你们有没有想法? 还是在C + + 11是不可能的?
有了模板和lambda,你可以这样做:
template <typename F> void common(F f) { foo(); bar(); f(); foobar(); } void MyFunction() { common([](){}); } void MyFunctionWithABonus() { common(&doBonusStuff); }
否则你可以创buildprefix
和suffix
函数。
void prefix() { foo(); bar(); } void suffix() { foobar(); } void MyFunction() { prefix(); suffix(); } void MyFunctionWithABonus() { prefix(); doBonusStuff(); suffix(); }
像这样的事情会很好地做到:
template<bool bonus = false> void MyFunction() { foo(); bar(); if (bonus) { doBonusStuff(); } foobar(); }
通过以下方式致电
MyFunction<true>(); MyFunction<false>(); MyFunction(); // Call myFunction with the false template by default
“丑”的模板可以通过添加一些漂亮的包装function来避免:
void MyFunctionAlone() { MyFunction<false>(); } void MyFunctionBonus() { MyFunction<true>(); }
你可以在那里find一些很好的信息。 这是一个“老”的论文,但技术本身保持完全正确。
假如你可以访问一个很好的C ++ 17编译器,那么你甚至可以推进这个技术,使用constexpr,如果这样的话:
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(); }
考虑到OP在debugging方面的一些评论,这里有一个版本调用doBonusStuff()
来debugging版本,但不是版本(定义NDEBUG
):
#if defined(NDEBUG) #define DEBUG(x) #else #define DEBUG(x) x #endif void MyFunctionWithABonus() { foo(); bar(); DEBUG(doBonusStuff()); foobar(); }
如果你想检查一个条件,你也可以使用assert
macros ,如果它是假的,就会失败(但只适用于debugging版本,发布版本不会执行检查)。
如果doBonusStuff()
有副作用,请小心,因为这些副作用将不会出现在发布版本中,并可能使代码中的假设无效。
这里是Jarod42的答案使用可变参数模板略有变化,所以来电者可以提供零或一个奖金function:
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(); }
调用代码:
MyFunction(); MyFunction(&doBonusStuff);
另一个版本,只使用模板,没有redirectfunction,因为你说你不想要任何运行时间的开销。 就像我担心的那样,这只会增加编译时间:
#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
现在只有一个带有bool
参数的MyFunc()
版本作为模板参数。
您可以使用标签调度和简单的函数重载:
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(); }
这很容易阅读/理解,可以没有汗水扩大( if
条款 – if
添加更多的标签,没有样板),当然也不会留下任何运行时间的痕迹。
调用语法相当友好,但当然可以包装成香草调用:
void MyFunctionAlone() { MyFunction(Tag_DisableBonus{}); } void MyFunctionBonus() { MyFunction(Tag_EnableBonus{}); }
标签调度是一个广泛使用的通用编程技术, 这里是一个很好的基础知识。