Skip to content

Instantly share code, notes, and snippets.

@maraigue
Created July 3, 2011 16:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maraigue/1062342 to your computer and use it in GitHub Desktop.
Save maraigue/1062342 to your computer and use it in GitHub Desktop.
「一言書くだけで末尾再帰最適化」をC++でやってみた
// 元ネタ:http://d.hatena.ne.jp/wasabiz/20110118/1295335821
//
// 注意点:
// ここで定義されているTCO_FUNCは、「末尾再帰で書かれた関数の引数が2つである場合」
// に限定された定義です。
// それ以上の場合は、別途マクロを定義しないとならないです。
// Boost.PPとかを使うと何とかなるのかな…?
#ifndef _OPT_TAIL_RECURSION_H_
#define _OPT_TAIL_RECURSION_H_
#define TCO_FUNC(FUNCTYPE, FUNCNAME, ARGTYPE1, ARGNAME1, ARGTYPE2, ARGNAME2) \
class FUNCNAME##_calculator__{ \
private: \
FUNCTYPE __result__; \
bool __tail_recursed__; \
ARGTYPE1 __##ARGNAME1##__; \
ARGTYPE2 __##ARGNAME2##__; \
\
public: \
FUNCNAME##_calculator__(ARGTYPE1 ARGNAME1, ARGTYPE2 ARGNAME2){ \
for(;;){ \
__tail_recursed__ = false; \
__result__ = (*this)(ARGNAME1, ARGNAME2); \
\
if(__tail_recursed__){ \
ARGNAME1 = __##ARGNAME1##__; ARGNAME2 = __##ARGNAME2##__; \
}else{ \
break; \
} \
} \
} \
\
FUNCTYPE FUNCNAME(ARGTYPE1 ARGNAME1, ARGTYPE2 ARGNAME2){ \
__##ARGNAME1##__ = ARGNAME1; \
__##ARGNAME2##__ = ARGNAME2; \
__tail_recursed__ = true; \
} \
\
FUNCTYPE operator ()(ARGTYPE1 ARGNAME1, ARGTYPE2 ARGNAME2); \
FUNCTYPE operator [](int dummy){ return __result__; } \
}; \
\
FUNCTYPE FUNCNAME(ARGTYPE1 ARGNAME1, ARGTYPE2 ARGNAME2){ \
FUNCNAME##_calculator__ calculator(ARGNAME1, ARGNAME2); \
return calculator[0]; \
} \
\
FUNCTYPE FUNCNAME##_calculator__::operator ()(ARGTYPE1 ARGNAME1, ARGTYPE2 ARGNAME2)
#endif // _OPT_TAIL_RECURSION_H_
#include <iostream>
#include "opt-tail-recursion.h"
TCO_FUNC(long long, sum1, long long, count, long long, acc){
if(count == 0) return acc;
return sum1(count - 1, acc + count);
}
long long sum2(long long count, long long acc){
if(count == 0) return acc;
return sum2(count - 1, acc + count);
}
/*
long long sum(long long count, long long acc = 0){
if(count == 0) return acc;
return sum(count - 1, acc + count);
}
*/
int main(void){
std::cout << sum1(1000000, 0) << std::endl;
std::cout << sum2(1000000, 0) << std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment