컴파일 타임에 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.