锘??xml version="1.0" encoding="utf-8" standalone="yes"?>
The following discussion focuses on C++-centric considerations, with Basic Tenets, Constraints, and Desiderata Garbage collection is desirable because: (1) It automates a routine and error-prone task (2) Reduces client code (3) Improves type safety (3) Can improve performance, particularly in multithreaded environments On the other hand, C++ idioms based on constructors and destructors, It follows that a set of principled methods that reconcile C++-style The constraints include compatibility with existing C++ code and styles A Causal Design Claim #1: The lifetime management of objects of a class is a decision of In support of this claim we come with the following examples: a) A class such as complex<double> is oblivious to destruction b) A class such as string doesn't need to worry about destruction c) A class such as temporary_file does need to worry about destruction In all of these examples, the context in which the objects are used is We'll therefore assume a C++ extension that allows a class definition to 聽
These two possible choices could be naturally complemented by the other 聽
It is illegal, however, that a class specifies both collected and 聽
Claim #2: Collected types cannot define a destruction-time action. This proposal makes this claim in wake of negative experience with Claim #3: Collected types can transitively only embed fields of If a collected type would have a field of a non-collected type, that If a collected type would have a field of pointer to a non-collected a) A dangling pointer access might occur; b) The resource is kept alive indeterminately and as such cannot be If a collected type would have a field of pointer to pointer to (notice Design fork #1: Weak pointers could be supported. A collected type could Claim #4: Deterministic types must track all pointers to their If deterministic types did allow untracked pointer copying, then Design branch #2: For type safety reasons, disallow type-erasing 聽 Or: For compatibility reasons, allow type-erasing conversion and incur Design branch #3: For purpose of having a type that stands in as a Design branch #3.1: std::deterministic may or may not define virtuals, Claim #5: When an object of deterministic type is constructed in If that didn't happen, dangling accesses to expired stack variables 聽 The desiderata set up and the constraints of the current C++ language * The class author decides whether the class is deterministic or garbage * As a natural extension, the class author can decide whether objects of * Depending on whether a type is deterministic versus collected, the * The heap is conceptually segregated into two realms. You can hold * The operations allowed on pointers to deterministic objects are Regime of Automatic Storage Claim 6: Pointers to either deterministic or collected objects that are This obvious claim prompts a search in look for an efficient solution to 聽 To address this problem a pointer/reference modifier, "auto", can be 聽 聽 If "auto"-modified pointers manipulated the reference count, their Does operator delete still exist? For collected objects, delete is inoperant, as is for static or Note that this makes delete entirely secure. There is no way to have a Regime of Static Storage Static storage has the peculiarity that it can easily engender This article delays discussion of the regime of static storage. Templates Claim #7: The collection regime of any type must be accessible during Here's a simple question: is vector<T> deterministic or collected? If it were collected, it couldn't hold deterministic types (because at So the right answer is: vector<T> has the same regime as T. 聽 After this design almost happening as a natural consequence of an Below are some considerations: * Pointer arithmetic, unions, and casts must be reconsidered (a source * Most types would be [collected]. Only a minority of types, those that * Efficiency of the system will not degrade compared to today's C++. The * Given that the compiler can apply advanced analysis to eliminate ---------------------- Whew! Please send any comments you have to this group. Thanks! Andrei 聽 聽 聽 [ See http://www.gotw.ca/resources/clcm.htm for info about ] Is it a mistake in TAOCP 瑕佽鐨勮瘽濂藉錛屽垪涓彁綰插厛
Andrei Alexandrescu (See Website For Email)
聽
2006騫?鏈?8鏃?鏄熸湡鍏? 涓嬪崍12鏃?3鍒?
"Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEm...@erdani.org>
comp.lang.c++.moderated
me at least. I've reached a number of conclusions that allow me to
better place the conciliation between garbage collection and
deterministic finalization in the language design space - in C++ and in
general.
occasional escapes into "the right thing to do if we could break away
with the past.
=========================================
including, but not limited to, scoped resource management, have shown to
be highly useful. The large applicability of such idioms might actually
be the single most important reason for which C++ programmers shy away
from migrating to a garbage-collected C++ environment.
programming based on object lifetime, with garbage collection, would be
highly desirable for fully exploiting garbage collection's advantages
within C++. This article discusses the challenges and to suggests
possible designs to address the challenges.
of coding, a preference for type safety at least when it doesn't
adversely incur a performance hit, and the functioning of today's
garbage collection algorithms.
===============
the class implementer, not of the class user.
timeliness because it does not allocate scarce resource that need timely
release;
timeliness within a GC (Garbage Collected) environment;
timeliness because it allocates scarce resources that transcend both the
lifetime of the object (a file handle) and the lifetime of the program
(the file on disk that presumably temporary_file needs to delete after
usage).
largely irrelevant (barring ill-designed types that employ logical
coupling to do entirely different actions depending on their state).
There is, therefore, a strong argument that the implementer of a class
decides entirely what the destruction regime of the class shall be. This
claim will guide design considerations below.
include its destruction regime:
//
聽garbage聽collected聽聽
聽 class聽[collected]聽Widget聽{...};聽
//聽deterministically聽destroyed聽聽
聽 class聽[deterministic]聽Midget聽{...};聽
聽
allowed storage classes of a class:
//
聽garbage聽collected聽or聽on聽stack聽聽
聽聽class聽[collected,聽auto]聽Widget聽{...};聽
//聽deterministically聽destroyed,聽stack,聽or聽static聽storage聽聽
聽聽class聽[deterministic,聽auto,聽static]聽Midget聽{...};聽
deterministic regime:
//
聽illegal聽聽
聽聽class聽[collected,聽deterministic]聽Wrong聽{...};聽
聽
Java's finalizers.
collected types (or pointers thereof of any depth), and can only derive
from such types.
type could not be destroyed (as per Claim #2).
type, one of two things happens:
destroyed (as per claim #2).
the double indirection) deterministic type, inevitably that pointer's
destination would have to be somehow accessible to the garbage-collected
object. This implies that at the some place in the points-to chain, a
"jump" must exist from the collected realm to the uncollected realm (be
it automatic, static, or deterministic) that would trigger either
post-destruction access, or would prevent the destructor to be called.
hold fields of type weak pointer to non-collected types. The weak
pointers are tracked and are zeroed automatically during destruction of
the resource that they point to. Further dereference attempts accesses
from the collected realm become hard errors.
respective objects (via a precise mechanism such as reference counting
or reference linking).
post-destruction access via dangling pointers might occur. The recent
discussion in the thread "Can GC be beneficial" has shown that it is
undesirable to define post-destruction access, and it's best to leave it
as a hard run-time error.
conversions from/to pointers to deterministic types:
聽聽聽Widget聽*聽p聽=聽new聽Widget;聽
聽聽聽void聽*聽p1聽=聽p;聽//聽error聽聽
聽聽聽p聽=聽static_cast<Widget聽*>(p1);聽//聽error,聽too聽
the risk of dangling pointer access.
pointer to any deterministic type (a sort of "deterministic void*"), all
deterministic classes could be thought as (or required to) inherit a
class std::deterministic.
and as such confines or not all deterministic classes to have virtuals
(and be suitable for dynamic_cast among other things).
automatic or static storage, its destructor will automatically issue a
hard error if there are any outstanding pointers to it (e.g., the
reference count is greater than one).
might occur:
聽Widget聽*聽p;聽
int聽Fun()聽
{聽
聽聽聽聽Widget聽w;聽
聽聽聽聽p聽=聽&w;聽
聽聽聽聽//聽hard聽runtime聽error聽upon聽exiting聽this聽scope聽


}聽
聽
==============================
created a causal chain that narrowly guided the possible design of an
integrated garbage collection + deterministic destruction in C++:
collected
that type are allowed to sit on the stack or in static storage. (The
regime of automatic and static storage will be discussed below.)
compiler generates different code for copying pointers to the object.
Basically the compiler automates usage of smart pointers, a
widely-followed semiautomatic discipline in C++.
unrestricted pointers to objects in the garbage-collected realm, but the
garbage-collected realm cannot hold pointers outside of itself.
restricted.
===========================
actually stack allocated should not escape the scope in which their
pointee object exists.
a class of problems. Here is an example: 
void聽Midgetize(Widget聽&聽obj)聽
{聽
聽聽聽聽obj.Midgetize();聽

}聽


void聽Foo()聽
{聽
聽聽聽聽Widget聽giantWidget;聽
聽聽聽聽Midgetize(giantWidget);聽

}聽
聽
Widget object even though the Midgetize function works on it
transitorily and stack allocation would suffice.
defined. Its semantics allow only "downward copying": an
pointer/reference to auto can only be copied to lesser scope, never to
object of larger scope. Examples: 
void聽foo()聽
{聽
聽聽聽聽Widget聽w;聽
聽聽聽聽Widget聽*auto聽p1聽=聽&w1;聽//聽fine,聽p1聽has聽lesser聽scope聽
聽聽聽聽
{聽
聽聽聽聽聽聽Widget聽*auto聽p2聽=聽&w;聽//聽fine聽
聽聽聽聽聽聽p2聽=聽p1;聽//聽fine聽
聽聽聽聽聽聽p1聽=聽p2;聽//聽error!聽Escaping聽assignment!聽
聽聽聽聽}聽


}聽
聽
this: 
void聽Midgetize(Widget聽&auto聽obj)聽
{聽
聽聽聽聽obj.Midgetize();聽

}聽


void聽Foo()聽
{聽
聽聽聽聽Widget聽giantWidget;聽
聽聽聽聽Midgetize(giantWidget);聽聽//聽fine聽

}聽
聽
from heap-allocated deterministic objects.
efficiency advantage would be lost. If they didn't, a type-unsafe
situation can easily occur.
=================================
automatic objects. On a heap-allocated deterministic object, delete can
simply check if the reference count is 1, and if so, reassign zero to
the pointer. If the reference count is greater than one, issue a hard 聽
error.
working program that issues a dangling access after delete has been 聽
invoked.
========================
post-destruction access. This is because the order of module
initialization is not defined, and therefore cross-module dependencies
among objects of static duration are problematic.
Hopefully with help from the community, a workable solution to the
cross-module initialization would ensue.
=========
compilation to templated code.
the end of the day vector<T> must embed a T*). If it were deterministic,
collected types couldn't hold vectors of pointers to collected types,
which would be a major and gratuitous restriction.
template聽<class聽T,聽class聽A>聽
class聽[T::collection_regime]聽vector聽
{聽//聽or聽some聽other聽syntax聽
聽聽聽...聽

};聽
聽
=====================================
initial set of constraints, the natural question arises: how would
programs look like in a C++ with these amenities?
of unsafety not thoroughly discussed)
manage non-memory resources, would live in the deterministic realm.
reduced need for reference-counted resources would allow free and fast
pointer copying for many objects; the minority that need care in
lifetime management will stay tracked by the compiler, the way they
likely were manipulated (by hand) anyway.
reference count manipulation in many cases, it is likely that the
quality of built-in reference counting would be superior to
manually-implemented reference counting, and on a par with advanced
manual careful manipulation of a mix of raw and smart pointers.
聽 聽 聽 [ comp.lang.c++.moderated. 聽 聽First time posters: Do this! ]
Maggie McLoughlin <mam@theory.stanford.edu> to Windreamer
to deal with empty sets and strings etc in a meaningful way.
If n = 0 and you're supposed to do something for 1 <= j <= n,
you don't have to do anything.
Thanks for your interest in my book! -- Don Knuth
鍛靛懙錛屽師鏉ユ槸鎴戝勾灝戞棤鐭ヤ簡錛屽啀嬈¤禐涓涓婯nuth鐖風埛鍐欎功鐨勭簿鑷?img src ="http://m.shnenglu.com/windreamer/aggbug/1814.html" width = "1" height = "1" />![]()
銆奣he Art of Computer Programming銆?/STRONG>鐨勭涓鍗?澶х悊鐭寵姳綰圭殑灝佺毊,鎷垮湪鎵嬮噷娌夌敻鐢哥殑,榪欓儴涔︾粰鎴戠殑絎竴鍗拌薄灝辨槸榪欐牱--"鍘氶噸"--甯︽湁鐫紲炵鎰熷拰鍘嗗彶鎰熴?BR>
鍏跺疄榪欓儴涔︾殑涓枃鐗堝墠璦,鎴戞棭灝辨湁騫告嫓璇昏繃,涓嶈繃鍜岃嫳鏂囧師鏂囩浉姣旇緝,鍦ㄤ腑鏂囩炕璇戠殑鍛抽亾鐪熺殑鏄樊浜嗗緢澶氾紝鎴戣寰楀彧鏈夎鍘熸枃鎵嶈兘鎰熷埌Knuth鐣ュ甫璇欒皭鐨勮屽張鍚屾槸涓嶆槸涓ヨ皚鐨勯鏍鹼紝浠栧啓鏂囩珷鐨勯鏍煎叾瀹炵湡鐨勬尯澶╅┈琛岀┖鐨勶紝浠庡啓紼嬪簭鎵埌鍋氶キ錛屼粠綆楁硶榪欎釜璇嶈亰璧鳳紝榪界潃榪欎釜璇嶇殑鏉ュ巻錛岀珶鐒惰繕甯﹀嚭浜嗚幈甯冨凹鑼紵鐪熸檿錛屽紑鍙ョ帺絎戯紝Knuth緇濆鏄偅縐嶈侀〗绔ュ瀷鐨勪漢鐗╋紝浠栬繖鏈功杈懼埌濡傛鍘氬害浼拌姝ょ被"搴熻瘽"鍔熶笉鍙病銆?BR>
浠嶢lgorithm鍒癊uclid's Algorithm涔熷氨鏄垜浠啛鎮夌殑杈楄漿鐩擱櫎姹傛渶澶у叕綰︽暟娉曪紝鎴戣繖涓畻娉曞皬鐧藉紑濮嬭繘鍏ヤ簡浠栨墦寮鐨勭畻娉曚笘鐣?.....
Knuth琛屾枃寰堝枩嬈㈡瘮杈冦佹瘮鍠匯佸姣旓紝榪欒璇昏呯湅璧鋒潵寰堣交鏉炬剦鎮︼紝涓嶈繃褰撲粬鐪熺殑鐜╄搗鏁板鏉ワ紝鎴戝氨鏈夌偣鍚冧笉娑堜簡錛屾渶鍚庨潰瀵圭畻娉曠殑涓涓艦寮忓寲鎻忚堪錛屾秷鑰椾簡鎴戜笉灝戠簿鍔涳紝涓嶈繃鐩墠鐪嬫潵榪樻槸澶ц嚧鏄庣櫧浜?IMG height=20 src="http://m.shnenglu.com/Emoticons/QQ/14.gif" width=20 border=0>
鎬諱箣錛岃繖鏈洓鍚嶄箣涓嬬殑涔︼紝涔熺殑紜湁寰堝鐙埌鐨勫湴鏂癸紝浣滀負璁$畻鏈虹瀛﹂鍩熺殑鍙茶瘲錛屽畠緇欐垜鐨勭涓鍗拌薄鐨勭‘寰堟銆傚笇鏈涙垜鑳藉潥鎸佺潃鐪嬩笅鍘伙紝浠庝腑鍚告敹钀ュ吇銆?BR>
铏界劧鍙湅浜嗕竴鑺傦紝涓嶈繃涔熸秷鑰椾簡鎴戜笉灝戠殑鏃墮棿鍜岀簿鍔涳紙鐪嬫潵鍒殑涓浜涗簨鎯呬篃涓嶈兘澶借錛屼篃瑕佹姄绱т簡錛?BR>
浠婂ぉ鐨勬敹鑾峰緢澶氾紝棣栧厛瀵圭畻娉曡繖涓悕璇嶆湁浜嗘洿澶氫竴浜涚殑鎰熸ц璇嗭紝Knuth鎻愬嚭鐨勨滄湁闄愩佹槑紜畾涔夈佹湁杈撳叆銆佹湁杈撳嚭銆佹湁鏁堢巼鈥濊繖鍑犱釜鍘熷垯鎬葷粨寰楃湡鏄笉閿欙紝灝ゅ叾鏈鍓嶉潰鐨勪袱鐐瑰拰鏁堢巼闂錛屽線寰鏋勬垚浜嗗緢澶氬鏉傜殑闂錛岃憲鍚嶇殑鍥劇伒鏈哄仠鏈洪棶棰樺ぇ姒傚氨鏄湪璇磋繖涓棶棰樺惂鈥︹?BR>
鍙﹀瀵逛簬杈楄漿鐩擱櫎娉曠殑涓浜涙暟瀛︿笂鐨勬帹瀵間篃緇欎簡鎴戜笉閿欑殑鎰熻錛岃櫧鐒朵功涓婃病鏈夋槑紜殑緇欎竴涓弗鏍肩殑璇佹槑錛屼絾鏄牴鎹粬鐨勫彊榪版垜椹笂灝變綋浼氬埌浜嗙敤姣旇緝涓ユ牸鐨勬柟娉曞浣曞啓榪欎釜璇佹槑錛屼互鍙婅繖涓瘉鏄庣殑鍏抽敭鐐癸紙鎴戣寰楄瘉鏄庝腑鍏跺疄鐢ㄥ埌浜嗛氳繃鍙屽寘鍚潵浜夌浉絳夌殑鎵嬫硶錛岃繖涓槸鍏抽敭錛?BR>
綆楁硶鐨勫艦寮忓寲鎻忚堪搴旇搗浜嗘垜澶х殑鍏磋叮錛屽洖鏉ョ殑璺笂鎯籌紝璨屼技榪欎釜濂藉儚褰㈡垚浜嗘煇縐嶆暟瀛︾粨鏋勶紝鑰屽叾涓婄殑f鏄犲皠錛屾瀯鎴愪簡鏌愮浠f暟緇撴瀯錛屾病鏈変粩緇嗘兂榪囷紝涓嶈繃濂藉儚鏄繖鏍峰瓙鐨勫摝錛屾垜瑙夊緱璨屼技綆楁硶鐨勬湰璐ㄥ氨鏄煇縐嶈嚜鍔ㄧ姸鎬佹満錛屽彧涓嶈繃涓嶄竴瀹氭槸鏈夐檺鐘舵佺殑鍚э紝鑷沖皯浠庝粬鐨勬剰鎬濅笂鐪嬫槸榪欐牱鐨?BR>
寮濮嬫病鏈夌悊瑙g浜屼釜錛屽姞涓婁簡鏁堢巼綰︽潫鐨勭殑褰㈠紡鍖栬〃杈炬柟娉曠殑鎰忔濓紝鍚庢潵鑺變簡鐐規椂闂寸湅浜嗕笅Ex1.1.8,鎴戣寰楁垜浼間箮鏄庣櫧浜嗙偣
鎴戣涓篍x1.1.8鏄繖鏍風殑涓涓姸鎬佽〃
j
Theta_j
Phi_j
a_j
b_j
0
a
a
5
1
1
ab
c
3
2
2
bc
cb
1
2
3
b
a
4
3
4
c
b
0
4
5
c
c
5
5
#include <iostream>
#include <string>
using namespace std;
int main ( int argc, char *argv[] )

{
// 0, 1, 2, 3, 4, 5
string theta[]=
{ "a", "ab", "cb", "b", "c", "c"};
string phi []=
{ "a", "c", "bc", "a", "b", "c"};
int a []=
{ 5, 3, 1, 4, 0, 5};
int b []=
{ 1, 2, 2, 3, 4, 5};
int j=0;
int i=0;
string stat;
getline (cin,stat);
while(true)
{
unsigned int loc=stat.find(theta[j],0);
if (loc==string::npos)
{
j=a[j];
}
else
{
string temp=stat.substr(0,loc)+phi[j]+stat.substr(loc+theta[j].length());
stat=temp;
j=b[j];
}
cout<<i++<<":\tj("<<j<<")\tloc("<<loc<<")\t"<<stat<<endl;
cin.get();
}
return EXIT_SUCCESS;
} /**//* ---------- end of function main ---------- */
蹇靛彣鍋氫竴涓硾鍨嬬殑綆楁硶搴撳凡緇忔湁濂介暱鏃墮棿浜嗭紝鎴戣寰楄繖涓簨鎯呬笌鍏朵竴鐩磋繖涔圷Y錛岃繕涓嶅楂樺叴浜嗗氨鍐欎竴鐐癸紝涓嶉珮鍏達紝灝辨墧鐫,
鍏跺疄錛岃繖涓笘鐣屾槸涓嶇己娉涘瀷綆楁硶搴撶殑錛孲TL錛孊oost錛孊litz++涓殑娉涘瀷綆楁硶寰堝叏闈簡錛屾垜鐨勮鍒掓槸鎶婁粬浠腑闂寸己灝戠殑閮ㄥ垎琛ヨ搗鏉ワ紝涓嶈兘浜掓搷浣滅殑鍦版柟綺樺悎璧鋒潵錛屽啀鏈夊氨鏄鍔犲MetaProgramming鐨勬敮鎸?BR> 鍛靛懙錛屽簲璇ヨ繕綆楁槸涓涓瘮杈冮泟浼熺殑璁″垝鍚?BR> 鎴戝笇鏈涜繖濂楀簱鑳藉敖鍙兘鐨勯珮鏁堢巼銆佸鏄撲嬌鐢ㄣ佸悓浜嬩繚璇佸畨鍏紝鐞嗘兂鐨勫鍦版槸鑳藉浠f浛ACM闆嗚闃熶嬌鐢ㄧ殑妯″潡
First Step鈥斺擡uclid GCD鐨勪竴涓疄鐜?
//-------------------------------BEGIN:GAlgo_Euclid_GCD.hpp--------------------------//
#ifndef _GAlgo_Euclid_GCD_H_
#define _GAlgo_Euclid_GCD_H_
namespace GAlgo

{
namespace Generic
{
template <typename T>
T Euclid_GCD(const T& a,const T& b)
{
return ((a%b)==0)?b:Euclid_GCD(b,a%b);
}
}
namespace Meta
{
template <int A,int B>
struct Euclid_GCD
{
static const int value=Euclid_GCD<B,A%B>::value;
};
template <int A>
struct Euclid_GCD<A,0>
{
static const int value=A;
};
}
}
#endif
//-------------------------------END:GAlgo_Euclid_GCD.hpp--------------------------//
#include "GAlgo_Euclid_GCD.hpp"
#include <iostream>
using namespace std;
int main()

{
cout<<GAlgo::Generic::Euclid_GCD(6,9)<<endl;
cout<<GAlgo::Meta::Euclid_GCD<6,9>::value<<endl;
return 0;
}
鍚岀被涔︾睄鎹垜鎵鐭ユ病鏈夊彲浠ヨ揪鍒拌繖涓珮搴︾殑錛屽ぇ閮ㄥ垎C++娉涘瀷鏂歸潰鐨勪笓钁楀彧灞闄愪簬鎬庝箞鐢⊿TL錛屽皢妯℃澘鍩虹鐨勪功錛屼篃浠呴檺浜庢渶琛ㄩ潰鐨勮娉曪紝鍍忔ā鐗堝弬鏁版帹瀵艱繖縐嶉棶棰橀矞鏈夋秹鍙婏紝鏇翠笉鐢ㄦ彁鍏充簬Metaprogramming錛岃繖鏈功鍦g粡鐨勫湴浣嶄及璁″悗浜轟篃鏄毦浠ヤ紒鍙婁簡銆?/P>
涓嬮潰鏄垜鐪嬩功鏃剁敾涓嬫潵鐨勪竴浜涜寰楄嚜宸卞鉤鏃跺簲璇ユ敞鎰忕殑鍦版柟錛屾斁鍦ㄨ繖閲屽仛澶囧繕濂戒簡
template <typename T>
inline T const& max (T const& a,T const& b);

max(4,7)//OK:T is int for both arguments
max(4,4.2)//ERROR:first T is int,second T is double
template <typename T,int VAL>
T addValue (T const& x)

{
return x+VAL
}
std::transform(source.begin(),source.end(),//start and end of source
dest.begin(),//start of destination
(int(*)(int const&))addValue<int,5>);//operation
template <int N>
void printBitset (std::bitset<N> const& bs)

{
std::cout<<bs.to_string<char,char_traits<char>,allacator<char> >();//ERROR:can't recogonize the template
}
template <int N>
void printBitset (std::bitset<N> const& bs)

{
std::cout<<bs.template to_string<char,char_traits<char>,allacator<char> >();//OK
}
template <typename T>
class Base

{
public:
void bar();
};
template <typename T>
class Derived : Base<T>

{
public:
void foo()
{
bar();//call external bar() or error
}
}
template <typename T>
class Derived : Base<T>

{
public:
void foo()
{
this->bar();//OK
}
}
template <typename T>
class IsClassT

{
private:
typedef char One;
typedef struct
{char a[2];} Two;
template <typename C> static One test (int::C*);
template <typename C> static Two test(
);
public:
enum
{Yes=sizeof(IsClassT<T>::test<T>(0))==1};
enum
{No=!Yes};
};
/**///////////////////////////////
//Prime.cpp
/**///////////////////////////////
template<int Val>
struct IntType

{
const static int value = Val ;
};
template<bool flag, typename T, typename U>
struct Select

{
typedef T Result;
};
template<typename T, typename U>
struct Select<false, T, U>

{
typedef U Result;
};
template <unsigned int N,unsigned int x>
struct FindRoot

{
const static int value=Select<(N/x)==x||((N/x+x)/2==x),IntType<x>,FindRoot<N,(N/x+x)/2> >::Result::value;
};
template <unsigned int N>
struct Sqrt

{
const static int value=FindRoot<N,N/2>::value;
};
template <>
struct Sqrt<0> ;
template <int N,int divider>
struct TestPrime

{
const static int value=Select<(N%divider)==0,IntType<0>,TestPrime<N,divider-1> >::Result::value;
};
template <int N>
struct TestPrime<N,1>

{
const static int value=1;
};
template <unsigned int N>
struct IsPrime

{
const static int value=TestPrime<N,Sqrt<N>::value+1>::value;
};
template <>
struct IsPrime<2>

{
const static int value=1;
};
template <>
struct IsPrime<1>;
int printf(const char*,
);
int main()

{
const int yes=IsPrime<123127>::value;
printf("%d\n",yes);
}