컴파일 타임에 1 + 2 + 3 +… + 1000을 계산하기 위해 C #, C ++ 또는 Java 컴파일러를 구동하는 방법은 무엇입니까?


122

최근 인터뷰에서 정말 이상한 질문을 받았습니다. 면접관은 컴파일러 기능을 사용하여 어떻게 1 + 2 + 3 + ... + 1000을 계산할 수 있는지 물었습니다. 즉, 프로그램을 작성하고 실행할 수는 없지만 컴파일 중에이 합계를 계산하고 컴파일이 완료되면 결과를 인쇄하도록 컴파일러를 구동 할 수있는 프로그램을 작성해야합니다. 힌트로 그는 컴파일러의 제네릭 및 전 처리기 기능을 사용할 수 있다고 말했습니다. C ++, C # 또는 Java 컴파일러를 사용할 수 있습니다. 어떤 아이디어 ???

이 질문은 여기에서 요청한 루프없이 합계를 계산하는 것과 관련이 없습니다 . 또한 합계는 컴파일 중에 계산되어야합니다. C ++ 컴파일러 지시문을 사용하여 결과 만 인쇄하는 것은 허용되지 않습니다.


게시 된 답변에 대해 더 많이 읽으면서 C ++ 템플릿을 사용하여 컴파일하는 동안 문제를 해결하는 것이 메타 프로그래밍 이라는 것을 알았습니다 . 이것은 C ++ 언어를 표준화하는 과정에서 Erwin Unruh 박사가 우연히 발견 한 기술입니다. 이 주제에 대한 자세한 내용 은 메타 프로그래밍의 위키 페이지 에서 읽을 수 있습니다 . Java 주석을 사용하여 Java로 프로그램을 작성할 수있는 것 같습니다. 아래 에서 maress의 답변을 볼 수 있습니다 .

C에서 메타 프로그래밍 ++에 대한 좋은 책은 이것 . 관심이 있다면 살펴볼 가치가 있습니다.

유용한 C ++ 메타 프로그래밍 라이브러리는 Boost의 MPL this link 입니다.


17
#error "500500"컴파일 오류가 "완료"로 간주됩니까?
Mysticial

4
힌트는 기본적으로 C ++ 템플릿을 사용하는 것을 의미합니다. 물론 동일하지만,이 일이 1000 일을 인쇄하지, 난 당신이 천 ...에 추가 수정할 수 있습니다 확신 stackoverflow.com/questions/4568645/...

8
const int value = 1 + 2 + 3.... + 1000; Console.WriteLine(value);; P
George Duckett 2012 년

8
때로는 인터뷰 질문이 인터뷰 대상자보다 면접관의 지적 우월성을 증명하기 위해 묻는다고 생각합니다.
Chris Dwyer

4
이 질문 받기 전에 많은 돈 을 요청 했습니까 ?
Salman A

답변:


118

향상된 재귀 깊이로 지금 업데이트 되었습니다! 깊이를 높이 지 않고 MSVC10 및 GCC에서 작동합니다. :)


간단한 컴파일 타임 재귀 + 추가 :

template<unsigned Cur, unsigned Goal>
struct adder{
  static unsigned const sub_goal = (Cur + Goal) / 2;
  static unsigned const tmp = adder<Cur, sub_goal>::value;
  static unsigned const value = tmp + adder<sub_goal+1, Goal>::value;
};

template<unsigned Goal>
struct adder<Goal, Goal>{
  static unsigned const value = Goal;
};

테스트 코드 :

template<unsigned Start>
struct sum_from{
  template<unsigned Goal>
  struct to{
    template<unsigned N>
    struct equals;

    typedef equals<adder<Start, Goal>::value> result;
  };
};

int main(){
  sum_from<1>::to<1000>::result();
}

GCC에 대한 출력 :

오류 : 'struct sum_from <1u> :: to <1000u> :: equals <500500u>'선언

Ideone의 라이브 예 .

MSVC10의 출력 :

error C2514: 'sum_from<Start>::to<Goal>::equals<Result>' : class has no constructors
      with
      [
          Start=1,
          Goal=1000,
          Result=500500
      ]

@hsalimi : 실제로 작업을 완료하는 일부 코드를 보여주기 위해 답변을 편집했습니다. :)
Xeo

와우, 당신은 정말 날 감동 :-)
굽타

@hsalimi : 1997 년 스톡홀름에서 열린 C ++ 표준화 회의에서이 기술을 발명 한 사람은 Erwin Unruh 박사였습니다. 그는 일련의 소수를 계산했습니다.
Dietmar Kühl

재귀없이 작동하게하려면 N * (N + 1) / 2 공식을 사용하여 합계를 계산할 수 있습니다.
Adam Gritt

2
@hsalimi C ++에서 템플릿 메타 프로그래밍의 훨씬 더 환상적인 예제를보고 싶다면 Andrei Alexandrescu의 Modern C ++ Design 을 제안 합니다.
Darhuuk

89

컴파일 타임에 오류에 대한 C # 예제.

class Foo
{
    const char Sum = (1000 + 1) * 1000 / 2;
}

다음 컴파일 오류를 생성합니다.

Constant value '500500' cannot be converted to a 'char' 

4
@ildjarn C ++ 템플릿 답변과이 답변 사이에는 차이가 있습니다. 여기서는 템플릿이 임의의 (?) 코드를 허용하는 동안 상수 접기 때문에 작동합니다. 문자에 할당하는 것이 좋습니다!
Voo

@Voo 예,하지만 공정하게 말하면 C #은 이러한 종류의 프로그래밍에 대해 C ++와 비교하지 않습니다.
Marlon

3
@Marion 그리고 저는 언어 디자인의 실수가 모두 강력 할 수 있다고 생각하지 않습니다.) 템플릿 메타 프로그래밍이 모두 강력 할 수 있지만 다른 언어는 여전히 모든 함정이없는 다른 솔루션으로 대부분의 작업을 수행 할 수 있습니다. 컴파일하는 데 몇 시간이 걸리고 (완전히 사실이 아닙니다. 재귀 인스턴스화 제한을 늘리지 않으면 믿을 수 없을 정도로 빠르며 .. 몇 초 만에 실패했습니다) 유지 관리가 끔찍한 프로젝트에서 작업해야했습니다. 아마도 내가 그것을 좋아하지 않는 이유
Voo

@Voo : FredOverflow의 접근 방식은 상수 접기에도 의존합니다. 느린 컴파일에 관해서는 언어가 아닌 컴파일러를 비난하십시오 (힌트-Clang은 C ++를 빠르게 컴파일합니다 ).
ildjarn

@ildjarn Clang은 매우 복잡하고 깊이 중첩되고 끔찍하게 복잡한 템플릿을 빠르게 컴파일합니까? 나는 모든 것이 가능하다고 가정하고 더 이상 테스트 할 수 없지만 (신에게 감사합니다) 상상할 수 없습니다. 또한 나는 Fred가 아니라 Xeo의 접근 방식에 대해 이야기하고 있습니다.
Voo

51

컴파일하는 동안이 합계를 계산하고 컴파일이 완료되면 결과를 인쇄하도록 컴파일러를 구동 할 수있는 프로그램을 작성해야합니다.

컴파일 중에 숫자를 인쇄하는 인기있는 트릭은 인쇄하려는 숫자로 인스턴스화 된 템플릿의 존재하지 않는 구성원에 액세스하려고하는 것입니다.

template<int> struct print_n {};

print_n<1000 * 1001 / 2>::foobar go;

그런 다음 컴파일러는 다음과 같이 말합니다.

error: 'foobar' in 'struct print_n<500500>' does not name a type

이 기법에 대한 더 흥미로운 예는 컴파일 타임에 8 개의 퀸 문제 해결을 참조 하십시오 .


print_n정의되지 않은 채로 두면 내 대답을 볼 수 있습니다.
Xeo

2
@David 그러나 Gauss는 영리한 방법이 필요했습니다. 그는 어리석은 방법으로 빠르게 처리 할 컴퓨터가 없었습니다.
Daniel Fischer 2012 년

31

인터뷰 질문에 컴파일러도 언어도 지정되지 않았기 때문에 GHC를 사용하여 Haskell에 솔루션을 제출할 수 있습니다.

{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS_GHC -ddump-splices #-}
module Main where

main :: IO ()
main = print $(let x = sum [1 :: Int .. 1000] in [| x |])

컴파일 :

$ ghc compsum.hs
[1 of 1] Compiling Main             ( compsum.hs, compsum.o )
Loading package ghc-prim ... linking ... done.
<snip more "Loading package ..." messages>
Loading package template-haskell ... linking ... done.
compsum.hs:6:16-56: Splicing expression
    let x = sum [1 :: Int .. 1000] in [| x |] ======> 500500
Linking compsum ...

그리고 우리는 또한 작동하는 프로그램을 얻었습니다.


20

constexpr현재 gcc 4.6 이상에서만 지원되지만 컴파일 시간 계산을위한 함수를 추가하는 C ++ 11을 사용하면 삶이 훨씬 더 쉬워 질 것 입니다.

constexpr unsigned sum(unsigned start, unsigned end) {
    return start == end ? start :
        sum(start, (start + end) / 2) +
        sum((start + end) / 2 + 1, end);
}

template <int> struct equals;
equals<sum(1,1000)> x;

표준은 컴파일러가 512의 재귀 깊이를 지원하도록 요구하므로 여전히 선형 재귀 깊이를 피해야합니다. 출력은 다음과 같습니다.

$ g++-mp-4.6 --std=c++0x test.cpp -c
test.cpp:8:25: error: aggregate 'equals<500500> x' has incomplete type and cannot be defined

물론 다음 공식을 사용할 수 있습니다.

constexpr unsigned sum(unsigned start, unsigned end) {
    return (start + end) * (end - start + 1) / 2;
}

// static_assert is a C++11 assert, which checks
// at compile time.
static_assert(sum(0,1000) == 500500, "Sum failed for 0 to 1000");

1
+1, constexpr잠시 동안 완전히 잊었습니다 . 템플릿을 너무 좋아할 수도 있습니다. :(
Xeo

이것은 질문을 해결하기위한 constexpr의 좋은 사용입니다 (Adder 구현 참조) : kaizer.se/wiki/log/post/C++_constexpr_foldr
Matt

그 공식은 넘칠 수 있습니다. 마지막 단계는 / 2가능한 unsigned결과 의 전체 범위를 처리하는 것이므로 오른쪽으로 이동하는 값은 n + 1 비트 너비 여야하지만 그렇지 않습니다. clang이 런타임 변수 범위에 대해 수행하는 것처럼이를 방지하기 위해 공식을 재 배열 할 수 있습니다. godbolt.org/z/dUGXqg 는 clang이 폐쇄 형 공식을 알고 total += i루프 를 최적화하는 데 사용한다는 것을 보여줍니다 .
Peter Cordes

14

Java에서는 주석 처리 사용에 대해 생각했습니다. apt 도구는 소스 파일을 실제로 javac 명령으로 구문 분석하기 전에 소스 파일을 스캔합니다.

소스 파일을 컴파일하는 동안 출력이 인쇄됩니다.

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface MyInterface {

    int offset() default 0;

    int last() default 100;
}

프로세서 공장 :

public class MyInterfaceAnnotationProcessorFactory implements AnnotationProcessorFactory {

    public Collection<String> supportedOptions() {
        System.err.println("Called supportedOptions.............................");
        return Collections.EMPTY_LIST;
    }

    public Collection<String> supportedAnnotationTypes() {
        System.err.println("Called supportedAnnotationTypes...........................");
        return Collections.singletonList("practiceproject.MyInterface");
    }

    public AnnotationProcessor getProcessorFor(Set<AnnotationTypeDeclaration> set, AnnotationProcessorEnvironment ape) {
        System.err.println("Called getProcessorFor................");
        if (set.isEmpty()) {
            return AnnotationProcessors.NO_OP;
        }
        return new MyInterfaceAnnotationProcessor(ape);
    }
}

실제 주석 프로세서 :

public class MyInterfaceAnnotationProcessor implements AnnotationProcessor {

    private AnnotationProcessorEnvironment ape;
    private AnnotationTypeDeclaration atd;

    public MyInterfaceAnnotationProcessor(AnnotationProcessorEnvironment ape) {
        this.ape = ape;
        atd = (AnnotationTypeDeclaration) ape.getTypeDeclaration("practiceproject.MyInterface");
    }

    public void process() {
        Collection<Declaration> decls = ape.getDeclarationsAnnotatedWith(atd);
        for (Declaration dec : decls) {
            processDeclaration(dec);
        }
    }

    private void processDeclaration(Declaration d) {
        Collection<AnnotationMirror> ams = d.getAnnotationMirrors();
        for (AnnotationMirror am : ams) {
            if (am.getAnnotationType().getDeclaration().equals(atd)) {
                Map<AnnotationTypeElementDeclaration, AnnotationValue> values = am.getElementValues();
                int offset = 0;
                int last = 100;
                for (Map.Entry<AnnotationTypeElementDeclaration, AnnotationValue> entry : values.entrySet()) {
                    AnnotationTypeElementDeclaration ated = entry.getKey();
                    AnnotationValue v = entry.getValue();
                    String name = ated.getSimpleName();
                    if (name.equals("offset")) {
                        offset = ((Integer) v.getValue()).intValue();
                    } else if (name.equals("last")) {
                        last = ((Integer) v.getValue()).intValue();
                    }
                }
                //find the sum
                System.err.println("Sum: " + ((last + 1 - offset) / 2) * (2 * offset + (last - offset)));
            }
        }
    }
}

그런 다음 소스 파일을 만듭니다. MyInterface 주석을 사용하는 간단한 클래스 :

 @MyInterface(offset = 1, last = 1000)
public class Main {

    @MyInterface
    void doNothing() {
        System.out.println("Doing nothing");
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        Main m = new Main();
        m.doNothing();
        MyInterface my = (MyInterface) m.getClass().getAnnotation(MyInterface.class);
        System.out.println("offset: " + my.offset());
        System.out.println("Last: " + my.last());
    }
}

주석 프로세서는 jar 파일로 컴파일되고 apt 도구는 소스 파일을 다음과 같이 컴파일하는 데 사용됩니다.

apt -cp "D:\Variance project\PracticeProject\dist\practiceproject.jar" -factory practiceproject.annotprocess.MyInterfaceAnnotationProcessorFactory "D:\Variance project\PracticeProject2\src\practiceproject2\Main.java"

프로젝트의 결과 :

Called supportedAnnotationTypes...........................
Called getProcessorFor................
Sum: 5000
Sum: 500500

9

다음은 VC ++ 2010에서 작동하는 구현입니다. 템플릿이 500 회 이상 반복 될 때 컴파일러가 불평했기 때문에 계산을 3 단계로 나눠야했습니다.

template<int t_startVal, int t_baseVal = 0, int t_result = 0>
struct SumT
{
    enum { result = SumT<t_startVal - 1, t_baseVal, t_baseVal + t_result +
        t_startVal>::result };
};

template<int t_baseVal, int t_result>
struct SumT<0, t_baseVal, t_result>
{
    enum { result = t_result };
};

template<int output_value>
struct Dump
{
    enum { value = output_value };
    int bad_array[0];
};

enum
{
    value1 = SumT<400>::result,                // [1,400]
    value2 = SumT<400, 400, value1>::result,   // [401, 800]
    value3 = SumT<200, 800, value2>::result    // [801, 1000]
};

Dump<value3> dump;

이것을 컴파일 할 때 다음과 같은 컴파일러의 출력을 볼 수 있습니다.

1>warning C4200: nonstandard extension used : zero-sized array in struct/union
1>          Cannot generate copy-ctor or copy-assignment operator when UDT contains a 
zero-sized array
1>          templatedrivensum.cpp(33) : see reference to class template 
instantiation 'Dump<output_value>' being compiled
1>          with
1>          [
1>              output_value=500500
1>          ]

그것을 분해하는 아주 좋은 아이디어, 나는 그것을 어떻게 든 내 대답에 통합 할 것이라고 생각합니다. +1 :
Xeo

9

아직 아무도 없었기 때문에이 C 코드를 제공 할 의무가 있다고 생각합니다.

#include <stdio.h>
int main() {
   int x = 1+2+3+4+5+6+7+8+9+10+11+12+13+14+15+16+17+18+19+20+
           21+22+23+24+25+26+27+28+29+30+31+32+33+34+35+36+37+38+39+40+
           41+42+43+44+45+46+47+48+49+50+51+52+53+54+55+56+57+58+59+60+
           61+62+63+64+65+66+67+68+69+70+71+72+73+74+75+76+77+78+79+80+
           81+82+83+84+85+86+87+88+89+90+91+92+93+94+95+96+97+98+99+100+     
           101+102+103+104+105+106+107+108+109+110+111+112+113+114+115+116+117+118+119+120+
           121+122+123+124+125+126+127+128+129+130+131+132+133+134+135+136+137+138+139+140+
           141+142+143+144+145+146+147+148+149+150+151+152+153+154+155+156+157+158+159+160+
           161+162+163+164+165+166+167+168+169+170+171+172+173+174+175+176+177+178+179+180+
           181+182+183+184+185+186+187+188+189+190+191+192+193+194+195+196+197+198+199+200+
           201+202+203+204+205+206+207+208+209+210+211+212+213+214+215+216+217+218+219+220+
           221+222+223+224+225+226+227+228+229+230+231+232+233+234+235+236+237+238+239+240+
           241+242+243+244+245+246+247+248+249+250+251+252+253+254+255+256+257+258+259+260+
           261+262+263+264+265+266+267+268+269+270+271+272+273+274+275+276+277+278+279+280+
           281+282+283+284+285+286+287+288+289+290+291+292+293+294+295+296+297+298+299+300+
           301+302+303+304+305+306+307+308+309+310+311+312+313+314+315+316+317+318+319+320+
           321+322+323+324+325+326+327+328+329+330+331+332+333+334+335+336+337+338+339+340+
           341+342+343+344+345+346+347+348+349+350+351+352+353+354+355+356+357+358+359+360+
           361+362+363+364+365+366+367+368+369+370+371+372+373+374+375+376+377+378+379+380+
           381+382+383+384+385+386+387+388+389+390+391+392+393+394+395+396+397+398+399+400+
           401+402+403+404+405+406+407+408+409+410+411+412+413+414+415+416+417+418+419+420+
           421+422+423+424+425+426+427+428+429+430+431+432+433+434+435+436+437+438+439+440+
           441+442+443+444+445+446+447+448+449+450+451+452+453+454+455+456+457+458+459+460+
           461+462+463+464+465+466+467+468+469+470+471+472+473+474+475+476+477+478+479+480+
           481+482+483+484+485+486+487+488+489+490+491+492+493+494+495+496+497+498+499+500+
           501+502+503+504+505+506+507+508+509+510+511+512+513+514+515+516+517+518+519+520+
           521+522+523+524+525+526+527+528+529+530+531+532+533+534+535+536+537+538+539+540+
           541+542+543+544+545+546+547+548+549+550+551+552+553+554+555+556+557+558+559+560+
           561+562+563+564+565+566+567+568+569+570+571+572+573+574+575+576+577+578+579+580+
           581+582+583+584+585+586+587+588+589+590+591+592+593+594+595+596+597+598+599+600+
           601+602+603+604+605+606+607+608+609+610+611+612+613+614+615+616+617+618+619+620+
           621+622+623+624+625+626+627+628+629+630+631+632+633+634+635+636+637+638+639+640+
           641+642+643+644+645+646+647+648+649+650+651+652+653+654+655+656+657+658+659+660+
           661+662+663+664+665+666+667+668+669+670+671+672+673+674+675+676+677+678+679+680+
           681+682+683+684+685+686+687+688+689+690+691+692+693+694+695+696+697+698+699+700+
           701+702+703+704+705+706+707+708+709+710+711+712+713+714+715+716+717+718+719+720+
           721+722+723+724+725+726+727+728+729+730+731+732+733+734+735+736+737+738+739+740+
           741+742+743+744+745+746+747+748+749+750+751+752+753+754+755+756+757+758+759+760+
           761+762+763+764+765+766+767+768+769+770+771+772+773+774+775+776+777+778+779+780+
           781+782+783+784+785+786+787+788+789+790+791+792+793+794+795+796+797+798+799+800+
           801+802+803+804+805+806+807+808+809+810+811+812+813+814+815+816+817+818+819+820+
           821+822+823+824+825+826+827+828+829+830+831+832+833+834+835+836+837+838+839+840+
           841+842+843+844+845+846+847+848+849+850+851+852+853+854+855+856+857+858+859+860+
           861+862+863+864+865+866+867+868+869+870+871+872+873+874+875+876+877+878+879+880+
           881+882+883+884+885+886+887+888+889+890+891+892+893+894+895+896+897+898+899+900+
           901+902+903+904+905+906+907+908+909+910+911+912+913+914+915+916+917+918+919+920+
           921+922+923+924+925+926+927+928+929+930+931+932+933+934+935+936+937+938+939+940+
           941+942+943+944+945+946+947+948+949+950+951+952+953+954+955+956+957+958+959+960+
           961+962+963+964+965+966+967+968+969+970+971+972+973+974+975+976+977+978+979+980+
           981+982+983+984+985+986+987+988+989+990+991+992+993+994+995+996+997+998+999+1000;
  printf("%d\n", x);
}

그리고 내가해야 할 일은 어셈블리를 확인하여 답을 찾는 것입니다!

gcc -S compile_sum.c;
grep "\$[0-9]*, *-4" compile_sum.s

그리고 나는 본다.

movl    $500500, -4(%rbp)

C 언어가 아닌 특정 구현의 기능입니다.
Puppy

5
C 의 "특정 구현"이 아닌 C 컴파일러를 얼마나 알고 있습니까?
Carl Walsh

@Puppy : x전역 적이라면 컴파일러는 컴파일 타임에 식을 평가하는 데 (다소) 필요합니다. ISO C는 전역에 대한 런타임 변수 이니셜 라이저를 허용하지 않습니다. 물론 특정 구현은 런타임에 계산하고 저장하는 생성자와 같은 static-init 함수를 호출 할 수 있습니다. 그러나 ISO C에서는 컴파일 시간 상수를 배열 크기 (예 int y[x];: 구조체 정의 또는 다른 전역)로 사용할 수 있으므로 가상의 비관적 구현은 여전히이를 지원해야합니다.
Peter Cordes

7

Carl Walsh의 답변에서 실제로 컴파일 중에 결과를 인쇄하도록 확장되었습니다.

#define VALUE (1+2+3+4+5+6+7+8+9+10+11+12+13+14+15+16+17+18+19+20+\
21+22+23+24+25+26+27+28+29+30+31+32+33+34+35+36+37+38+39+40+\
41+42+43+44+45+46+47+48+49+50+51+52+53+54+55+56+57+58+59+60+\
61+62+63+64+65+66+67+68+69+70+71+72+73+74+75+76+77+78+79+80+\
81+82+83+84+85+86+87+88+89+90+91+92+93+94+95+96+97+98+99+100+\
101+102+103+104+105+106+107+108+109+110+111+112+113+114+115+116+117+118+119+120+\
121+122+123+124+125+126+127+128+129+130+131+132+133+134+135+136+137+138+139+140+\
141+142+143+144+145+146+147+148+149+150+151+152+153+154+155+156+157+158+159+160+\
161+162+163+164+165+166+167+168+169+170+171+172+173+174+175+176+177+178+179+180+\
181+182+183+184+185+186+187+188+189+190+191+192+193+194+195+196+197+198+199+200+\
201+202+203+204+205+206+207+208+209+210+211+212+213+214+215+216+217+218+219+220+\
221+222+223+224+225+226+227+228+229+230+231+232+233+234+235+236+237+238+239+240+\
241+242+243+244+245+246+247+248+249+250+251+252+253+254+255+256+257+258+259+260+\
261+262+263+264+265+266+267+268+269+270+271+272+273+274+275+276+277+278+279+280+\
281+282+283+284+285+286+287+288+289+290+291+292+293+294+295+296+297+298+299+300+\
301+302+303+304+305+306+307+308+309+310+311+312+313+314+315+316+317+318+319+320+\
321+322+323+324+325+326+327+328+329+330+331+332+333+334+335+336+337+338+339+340+\
341+342+343+344+345+346+347+348+349+350+351+352+353+354+355+356+357+358+359+360+\
361+362+363+364+365+366+367+368+369+370+371+372+373+374+375+376+377+378+379+380+\
381+382+383+384+385+386+387+388+389+390+391+392+393+394+395+396+397+398+399+400+\
401+402+403+404+405+406+407+408+409+410+411+412+413+414+415+416+417+418+419+420+\
421+422+423+424+425+426+427+428+429+430+431+432+433+434+435+436+437+438+439+440+\
441+442+443+444+445+446+447+448+449+450+451+452+453+454+455+456+457+458+459+460+\
461+462+463+464+465+466+467+468+469+470+471+472+473+474+475+476+477+478+479+480+\
481+482+483+484+485+486+487+488+489+490+491+492+493+494+495+496+497+498+499+500+\
501+502+503+504+505+506+507+508+509+510+511+512+513+514+515+516+517+518+519+520+\
521+522+523+524+525+526+527+528+529+530+531+532+533+534+535+536+537+538+539+540+\
541+542+543+544+545+546+547+548+549+550+551+552+553+554+555+556+557+558+559+560+\
561+562+563+564+565+566+567+568+569+570+571+572+573+574+575+576+577+578+579+580+\
581+582+583+584+585+586+587+588+589+590+591+592+593+594+595+596+597+598+599+600+\
601+602+603+604+605+606+607+608+609+610+611+612+613+614+615+616+617+618+619+620+\
621+622+623+624+625+626+627+628+629+630+631+632+633+634+635+636+637+638+639+640+\
641+642+643+644+645+646+647+648+649+650+651+652+653+654+655+656+657+658+659+660+\
661+662+663+664+665+666+667+668+669+670+671+672+673+674+675+676+677+678+679+680+\
681+682+683+684+685+686+687+688+689+690+691+692+693+694+695+696+697+698+699+700+\
701+702+703+704+705+706+707+708+709+710+711+712+713+714+715+716+717+718+719+720+\
721+722+723+724+725+726+727+728+729+730+731+732+733+734+735+736+737+738+739+740+\
741+742+743+744+745+746+747+748+749+750+751+752+753+754+755+756+757+758+759+760+\
761+762+763+764+765+766+767+768+769+770+771+772+773+774+775+776+777+778+779+780+\
781+782+783+784+785+786+787+788+789+790+791+792+793+794+795+796+797+798+799+800+\
801+802+803+804+805+806+807+808+809+810+811+812+813+814+815+816+817+818+819+820+\
821+822+823+824+825+826+827+828+829+830+831+832+833+834+835+836+837+838+839+840+\
841+842+843+844+845+846+847+848+849+850+851+852+853+854+855+856+857+858+859+860+\
861+862+863+864+865+866+867+868+869+870+871+872+873+874+875+876+877+878+879+880+\
881+882+883+884+885+886+887+888+889+890+891+892+893+894+895+896+897+898+899+900+\
901+902+903+904+905+906+907+908+909+910+911+912+913+914+915+916+917+918+919+920+\
921+922+923+924+925+926+927+928+929+930+931+932+933+934+935+936+937+938+939+940+\
941+942+943+944+945+946+947+948+949+950+951+952+953+954+955+956+957+958+959+960+\
961+962+963+964+965+966+967+968+969+970+971+972+973+974+975+976+977+978+979+980+\
981+982+983+984+985+986+987+988+989+990+991+992+993+994+995+996+997+998+999+1000)

char tab[VALUE];

int main()
{
    tab = 5;
}

gcc 출력 :

test.c: In function 'main':
test.c:56:9: error: incompatible types when assigning to type 'char[500500]' fro
m type 'int'

2

메타 프로그래밍 을 수행하기 위해 C ++ 매크로 / 템플릿을 사용할 수 있습니다 (대부분 남용) . AFAIK, Java는 같은 종류의 것을 허용하지 않습니다.


2
질문에 대한 답이 아닙니다.
Ikke

그 쪽이 맞는 거 같아요. 자바에서는 일반 클래스 매개 변수가 값이 될 수 없기 때문에 동일한 템플릿 재귀 트릭을 사용할 수 없습니다. 클래스 여야합니다.
Eyal Schneider

C # 컴파일러의 제네릭 기능을 사용하면 몇 가지 컴파일 시간 계산을 수행 할 수 있습니다. 이에 대한 Eric Lippert의 게시물을 참조하십시오 .
Allon Guralnek

1

이론적으로 다음을 사용할 수 있습니다.

#include <iostream>

template<int N>
struct Triangle{
  static int getVal()
  {
    return N + Triangle<N-1>::getVal();
  }
};

template<>
struct Triangle<1>{
  static int getVal()
  {
    return 1;
  }
};

int main(){
   std::cout << Triangle<1000>::getVal() << std::endl;
   return 0;
}

(Xeo가 게시 한 코드를 기반으로 함). 그러나 GCC는 다음과 같은 오류를 제공합니다.

triangle.c++:7: error: template instantiation depth exceeds maximum of 500 (use -ftemplate-depth-NN to increase the maximum) instantiating struct Triangle<500>

또한 엄청난 의사 스택 추적이 있습니다.


다음 플래그를 사용해야합니다. -ftemplate-depth-1000
Jetti

@hsalimi : 네. 플래그를 추가하면 1000에서도 작동합니다. 그러나 그것은 컴파일 타임에 인쇄되지 않으며 Xeo는 실제로이 특정 문제에 대답하기 위해 대답을 변경했기 때문에 제 대답은 쓸모 가 없다고 생각합니다. :-)
ruakh

1

Java를 사용하면 C # 답변과 비슷한 작업을 수행 할 수 있습니다.

public class Cheat {
    public static final int x = (1000 *1001/2);
}

javac -Xprint Cheat.java

public class Cheat {

  public Cheat();
  public static final int x = 500500;
}

피노 숫자를 사용하여 스칼라 에서 이것을 할 수 있습니다.컴파일러가 재귀를 수행하도록 할 수 있기 때문에 할 수 있지만 C # / java에서 똑같은 일을 할 수 있다고 생각하지 않습니다.

-Xprint를 사용하지 않는 또 다른 솔루션이지만 더 이상합니다.

public class Cheat {
  public static final int x = 5/(1000 *1001/2 - 500500);
}

javac -Xlint:all Cheat.java

Cheat.java:2: warning: [divzero] division by zero
  public static final int x = 5/(1000 *1001/2 - 500500);
                            ^
1 warning

컴파일러 플래그를 사용하지 않고. 임의의 수의 상수 (500500이 아님)를 확인할 수 있으므로이 솔루션은 허용됩니다.

public class Cheat {
  public static final short max = (Short.MAX_VALUE - 500500) + 1001*1000/2;
  public static final short overflow = (Short.MAX_VALUE - 500500 + 1) + 1001*1000/2;

}

Cheat.java:3: error: possible loss of precision
  public static final short overflow = (Short.MAX_VALUE - 500500 + 1) + 1001*1000/2;
                                                                  ^
  required: short
  found:    int
1 error

컴파일러 가을 계산 하도록 구동하지 않았습니다 500500. 죄송합니다.
Xeo

1
이것은 세 가지 솔루션 모두와 관련이 있습니까? 솔루션 1에서 Java 코드를 가져와 컴파일하고 컴파일러가 500500을 출력했습니다. 이는 컴파일러가 500500을 컴퓨팅하는 것과 비슷합니다. 이것이 컴파일러가 500500을 컴퓨팅하지 않는 이유는 무엇입니까?
benmmurphy

네, 충분히 사실입니다. 저는 솔루션 2와 3에 대해 이야기하고있었습니다. 이전 업데이트에서이 답변을 이미 읽었고 최신 업데이트로 돌아 왔고 어떻게 든 첫 번째 솔루션을 잊어 버린 것 같습니다.
Xeo

나는 솔루션 2 & 3도 그것을 계산한다고 말할 것입니다. 임의의 수의 검사를 추가 할 수 있으므로 기본적으로 수행하고 for (i = 0; i < 100000; ++i) {if (i == 1000*1000/2) print i}있습니다. 나는이 작업을 수행하는 160메가바이트 자바 파일을 가지고 있고 그것은 : 작동
benmmurphy

1

이것은 실제로 작은 숫자로 작동하지만 N> 400 인 sum_first를 사용하는 경우 clang ++에서 컴파일러 오류를 반환합니다.

#include <iostream>

using namespace std;


template <int N>
struct sum_first
{
   static const int value = N + sum_first<N - 1>::value;
};

template <>
struct sum_first<0>
{
    static const int value = 0;
};

int main()
{
    cout << sum_first<1000>::value << endl;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.