constexpr ã¡ã¿ããã°ã©ãã³ã°:ãéåºŠãæ¬²ããã⊠ãªãã°ãããŠãã!ã
source: http://cpptruths.blogspot.com/2011/07/want-speed-use-constexpr-meta.html
å
¬çã«C++11ã¯äºçš®ã®ã¡ã¿ããã°ã©ãã³ã°æ¹æ³ãåããŠãããã²ãšã€ã¯templateããŒã¹ã§ãããã²ãšã€ã¯constexprã§ããã(蚳蚻ïŒCPPã©ããã£ãâŠ!) templateã¯C++03ã§ã¯åºãã¡ã¿ããã°ã©ãã³ã°ã«çšããããŠãããC++11ã§ã¯ããã²ãšã€éžæè¢ãå ãããconstexprãçšããã³ã³ãã€ã«ã¿ã€ã ã¡ã¿ããã°ã©ãã³ã°ã§ãããã ãããããã¯æ©èœæ§ã»å¯çšæ§ã®ç¹ã§çžéãããã
templateãå©çšããã¡ã¿ããã°ã©ãã³ã°ã¯ãŸã£ããã®å¶ç¶ããçºèŠããã以æ¥ãçš®ã
倿§ãªãã¯ããã¯ãçºæããã€ã¥ããŠãããããã¯ãæŽæ°ãªãã©ã«ãšåã®ã³ã³ãã€ã«ææäœãå¯èœãªäžæ¹ã§ãæµ®åå°æ°ç¹æ°ãªãã©ã«ãæ±ããªãçŽç²é¢æ°åèšèªãšããŠæ©èœãããtemplateã¡ã¿ããã°ã©ãã³ã°ã®æ§æã¯ãã¡ã¿é¢æ°ãæ§é äœããããã¯å
¥ãåã®typedefã§å®è£
ããªããã°ãªãããéåžžã«èŠèŠãããšæããè
ãå€ãã£ãã
æ±åããã宿°åŒ(ä»¥äž constexpr)ã¯C++11ã«å¯Ÿå¿ããã³ã³ãã€ã©ãã颿°ã®(ããã«ã¯ã¯ã©ã¹ã®)å®è£
ã調ã¹ãŠããã颿°(ãšã¯ã©ã¹)ã宿°(ãªãã©ã«)ã®ã¿ã䜿ã£ãŠããå Žåã«æé©åã§ããããã«ããæ©èœã§ããããã®å Žåã宿°ã¯æŽæ°ãªãã©ã«ã§ãæµ®åå°æ°ç¹æ°ãªãã©ã«ã§ãæååãªãã©ã«ã§ããããconstexprãã€ãã颿°ã¯æ®éã®C++颿°ãšåãããã«èŠãããã颿°æ¬æã¯åäžã®returnæããèš±å¯ãããªããšããå¶éããããããã«ããŠããconstexpr颿°ã®æ§æã¯templateããŒã¹ã®ã¡ã¿é¢æ°ããã¯ããã«ãšã£ã€ãããããtemplateãå°å
¥ããããšããšã¯å¯Ÿç
§çã«ãæ±åããã宿°åŒã®èšèšè
ã¯ãããããã®ã¡ã¿ããã°ã©ãã³ã°èœåãååçè§£ããŠããã
æãã«ãconstexprã®ç ç®ãã¹ãæ§è³ªã¯ãã®é床ã«ãããconstexpr颿°ã¯ã³ã³ãã€ã«æã«é»å
ç³ç«ã®ããšãé床ã§èšç®ãè¡ãªããããã©ãŒãã³ã¹ãæ¯èŒããããã«ãçè
ã¯is_prime ã¢ã«ãŽãªãºã ã3çš®ã®æ¹æ³ã§å®è£
ããããŸã以äžã¯éåžžã®C++ã§å®è£
ãããã®ã§ããïŒ
static bool IsPrime(size_t number) { if (number <= 1) return false; for (size_t i = 2; i*i <= number; ++i) if (number % i == 0) return false; return true; }
ã€ãã«ãåãã¢ã«ãŽãªãºã ãtemplateã§å®è£
ãããã®ã瀺ããèšããŸã§ããªããæ§é äœãåºæ¬ãšããã¡ã¿é¢æ°ã®ãã€ãŸããšããŠå®è£
ããã
struct false_type { typedef false_type type; enum { value = 0 }; }; struct true_type { typedef true_type type; enum { value = 1 }; }; template<bool condition, class T, class U> struct if_ { typedef U type; }; template <class T, class U> struct if_<true, T, U> { typedef T type; }; template<size_t N, size_t c> struct is_prime_impl { typedef typename if_<(c*c > N), true_type, typename if_<(N % c == 0), false_type, is_prime_impl<N, c+1> >::type >::type type; enum { value = type::value }; }; template<size_t N> struct is_prime { enum { value = is_prime_impl<N, 2>::type::value }; }; template <> struct is_prime<0> { enum { value = 0 }; }; template <> struct is_prime<1> { enum { value = 0 }; };
ãã®ã¡ã¿ããã°ã©ã ã¯çŽç²é¢æ°åèšèªã«åã£ãŠååž°çå®è£
ãåã£ãŠããããã® is_prime_impleã¡ã¿é¢æ°ãéèŠãªä»äºããã¹ãŠãã£ã€ããŠãããç¡éååž°ãé²ãããã«ã"æ æ°ãªã€ã³ã¹ã¿ã³ã¹å(lazy instatiation)"ãã¯ããã¯ãçšããŠãããæãã«ããã£ãšä»èªè
ã¯ã³ãŒããåèŠããŠçè§£ã«åªããŠããããšã ããã
âŠããããããããçãã ãèŠã¯C++03ã®ã¡ã¿ããã°ã©ã ã¯ã ãããèªã¿ã¥ãããçè§£ãã¥ããã®ã ãâŠæã¯æ¥ããã! 以äžã¯åãã¢ã«ãŽãªãºã ãconstexprã§å®è£
ãããã®ã§ããã
constexpr bool is_prime_recursive(size_t number, size_t c) { return (c*c > number) ? true : (number % c == 0) ? false : is_prime_recursive(number, c+1); } constexpr bool is_prime_func(size_t number) { return (number <= 1) ? false : is_prime_recursive(number, 2); }
ããããŸãèšãããããšã¯åããããã®ãŽã¡ãŒãžã§ã³ã§ããŸã ããã»ã©èªã¿ããããšã¯èšããªããtemplateçãšåæ§ããã¡ããååž°ã䜿ã£ãŠãããããã¯ãããããŠéŠŽããŸããã! C++ã®ã¡ã¿ããã°ã©ãã³ã°ã«ãããŠã¯ãååž°ã¯åã£ãŠãåããªãé¢ä¿ã«ããã®ã§ä»æ¹ãªãããŸããå
šãŠã®é¢æ°ã¯åäžã®returnæããæã£ãŠããããçŽ æ°ãæ€åºããéã®æ¡ä»¶åå²ã«æ¡ä»¶æŒç®å(蚳蚻ïŒåæternary operatorã§âŠ)ãå€çšãããŠããã
å®åŒæ°ãæŽæ°å®æ°ãªãã°ãconstexprçã¯(ãã¡ããC++11察å¿ã®ã³ã³ãã€ã©ãªãã°)ã³ã³ãã€ã«æã«çµæãã§ãããŸããå®åŒæ°ãã©ã³ã¿ã€ã ã«æ±ºå®ãããå Žåã§ããåã颿°ã䜿ã£ãŠå®è¡æã«èšç®ãåé¡ãªãçµæãåºãããšãã§ãããã€ãŸããã³ã³ãã€ã«ã¿ã€ã ãšã©ã³ã¿ã€ã çšã«äºã€åãããšãããããã°ã©ã ãæžãå¿
èŠããªããããã²ãšã€ã§å
šãŠãå¶ãã®ã !
int main(void) { int i = is_prime_func(7); // Computed at compile-time int j = is_prime_func(i); // Computed at run-time }
ããŠãå®è£
ãçµãã£ããšããã§ãããã©ãŒãã³ã¹ã®è©±ã«ç§»ããã4256233ãäŸãšããŠæããããããã¯äžäžçªç®ã®çŽ æ°ã ããããçŽ æ°ãã©ãã確èªããã®ã«ãtemplateçã ãšã©ã®ãããæãã ããããâŠã ããã¡ã£âŠ! ãã以åã®åé¡ã§ãg++4.7ã§ã¯is_prime<4256233>::valueãã³ã³ãã€ã«ã§ããªãããšããã®ã¯ãååž°ãã³ãã¬ãŒãã€ã³ã¹ã¿ã³ã¹åã®äžéãããã©ã«ãã§ã¯900åã«çžãããŠããããã ãæ°ããšããªãã㊠-ftemplate-depth-2100 ã䜿ã£ãŠ2100åãŸã§ååž°ã§ããããã«ããŠã¿ãããâŠã€ã±ããâŠïŒ ã€ã±ã! ããã©ã®ãããæéãæã£ãã ããããâŠã ãããäžç§ã ! âŠãŸãæªããªããããšèªè
ã¯æããããããªããã§ã¯constexprã§ã¯ã©ããããªããšè
åšã®0.154ç§ã !
ããã ãšããã»ã©templateçãé
ãããã«ã¯èŠããªããããããªãã倧ééãã ãäºåäžåç®ã®çŽ æ°ã«ã€ããŠèããŠã¿ããã982451653ã ãg++4.7ã§ã¯åäœãããããšããã§ããªãã£ãã8000åç®ãããã®ãã³ãã¬ãŒãã€ã³ã¹ã¿ã³ã¹åã§g++ã¯ã»ã°ãã©ãåããããããã¢ã³ãã§ã¢ã ! ãšæããããããªãã8000+åã®ååž°ãã³ãã¬ãŒãã€ã³ã¹ã¿ã³ã¹åãïŒãã£ãšãã·ãªæ¹æ³ãããã«éããªãã
ããŠãã§ã¯constexprçã§äºåäžåç®ã®çŽ æ°ãå€å®ããŠã¿ãã⊠ãªããš0.154ç§ã ã£ã! ééããªããtypoãããŠããªã! ãã®å·šå€§ãªçŽ æ°ã以ã£ãŠããã³ã³ãã€ã«æéã«äžãã圱é¿ã¯ã»ãšãã©ãªããåç¶ã ã£ãããã£ããã©ãããèš³ã ããããŸããconstexprçã«ã¯ãã³ãã¬ãŒãã®ã€ã³ã¹ã¿ã³ã¹åã䌎ãªããªããC++ã³ã³ãã€ã©ã¯ã§ããéãã³ã³ãã€ã«æèšç®ãããããšãããconstexprã¯ãŠãŒã¶ãŒå®çŸ©ã®æœè±¡å(user-defined abstractions)ã®æ©äŒãäžãã颿°ã®åŸãã«èšç®ãé ãã€ã€ãã³ã³ãã€ã©ããèŠéããããã«ãªããããã²ãšã€ãã®é»å
ç³ç«ã®ããã©ãŒãã³ã¹ãã§ãããªçç±ã¯ãis_prime_funcã¯æ«å°Ÿååž°é¢æ°ã ãšããç¹ã ãããã¯ãåªããã³ã³ãã€ã©ãªãã³ã³ãã€ã«ã¿ã€ã ã«ååž°ãå®å
šã«çããŠåçŽãªã«ãŒãã«å¹³æ¿åã§ãããšããäºãæå³ããã
ãã®ç°¡åãªãµã³ãã«ã§ããªãã©ã«(æŽæ°ãæµ®åå°æ°ç¹æ°ãæåå)ãåŠçããéãã«ãããŠãconstexprã¯C++ã®éçã¡ã¿ããã°ã©ãã³ã°ã®é²ãã¹ãéã瀺ããŠãããšç¢ºä¿¡ããŠããã ããã°å¹žãã§ãããconstexpr颿°ã§è€éãªã¡ã¿ããã°ã©ã å¯èœãªåãäŸãã°mpl::containsãmpl::push_backãªã©ãããŸãæ±ãããã©ãããŸã ããåãããªããããèå³ã沞ããŠãäžèšã®ãµã³ãã«ã³ãŒãã§éãã§ã¿ããå Žåã¯ããã¡ã(is_prime.cpp prime-test.sh)ã«çœ®ããŠããã