【问题标题】:How to drive C#, C++ or Java compiler to compute 1+2+3+...+1000 at compile time?如何在编译时驱动 C#、C++ 或 Java 编译器计算 1+2+3+...+1000?
【发布时间】:2012-02-04 12:24:03
【问题描述】:

在最近的一次采访中,我被问到一个非常奇怪的问题。面试官问我如何仅使用编译器功能计算 1+2+3+...+1000。这意味着我不允许编写程序并执行它,但我应该只编写一个程序,该程序可以驱动编译器在编译时计算这个总和,并在编译完成时打印结果。作为提示,他告诉我我可以使用编译器的泛型和预处理器特性。可以使用 C++、C# 或 Java 编译器。有什么想法???

这个问题与在没有任何循环的情况下计算总和 asked here 无关。此外,需要注意的是,总和应该在编译期间计算。使用 C++ 编译器指令仅打印结果是不可接受的。


阅读有关已发布答案的更多信息,我发现使用 C++ 模板在编译期间解决问题称为元编程。这是 Erwin Unruh 博士在标准化 C++ 语言的过程中偶然发现的一种技术。您可以在wiki page of meta-programming 上阅读有关此主题的更多信息。 似乎可以使用 Java 注释在 Java 中编写程序。您可以看看下面的 maress's 答案。

一本关于 C++ 元编程的好书是this one。有兴趣的值得一看。

一个有用的 C++ 元编程库是 Boost 的 MPL this link

【问题讨论】:

  • #error "500500" 编译错误算作“完成”吗?
  • 提示本质上意味着您可以使用 C++ 模板。显然不一样,但这个是打印 1 到 1000,我相信你可以修改它以添加到 1000...stackoverflow.com/questions/4568645/…
  • const int value = 1 + 2 + 3.... + 1000; Console.WriteLine(value); ;P
  • 有时我认为问一些面试问题只是为了证明面试官的智力优于被面试者。
  • 在被问到这个问题之前,您是否要求很多钱

标签: c# java c++ compiler-construction metaprogramming


【解决方案1】:

更新现在提高了递归深度!适用于 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::to::equals’的声明

Live example on Ideone.

MSVC10 的输出:

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

【讨论】:

  • @hsalimi:我编辑了答案以实际显示一些完成工作的代码。 :)
  • 哇,你真的给我留下了深刻的印象:-)
  • @hsalimi:是 Erwin Unruh 博士在 1997 年斯德哥尔摩 C++ 标准化会议上发明了这项技术。他计算了一系列素数。
  • 要使其在没有递归的情况下工作,您可以使用 N*(N+1)/2 的公式来计算总和。
  • @hsalimi 如果您想看到更多精彩的 C++ 模板元编程示例,我建议您使用 Andrei Alexandrescu 的 Modern C++ Design
【解决方案2】:

编译时出错的 C# 示例。

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

产生以下编译错误:

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

【讨论】:

  • @ildjarn 好吧,c++ 模板答案和这个答案是有区别的:这只是因为不断折叠而有效,而模板允许任意 (?) 代码。将其分配给 char 仍然是个好主意!
  • @Voo 是的,但公平地说,C# 在这种编程方面无法与 C++ 相比。
  • @Marion 而且我真的不认为这是语言设计中的错误;)模板元编程可能非常强大,但其他语言仍然可以用其他解决方案完成大部分事情没有所有这些陷阱。我不得不在一个需要几个小时才能编译的项目上工作(不完全正确 - 如果我们不增加递归实例化限制,它会非常快......它在几秒钟内就失败了)并且维护起来很糟糕。可能是我不太喜欢它的一个原因..
  • @Voo :FredOverflow 的方法也依赖于常量折叠。至于慢编译,怪你的编译器,而不是语言(提示——Clang 编译 C++ fast)。
  • @ildjarn Clang 可以快速编译极其复杂、嵌套非常深且极其复杂的模板?我假设一切皆有可能,但我无法再测试它(感谢上帝),但我无法想象。另外我说的是 Xeo 的方法,而不是 Fred 的方法。
【解决方案3】:

我应该只写一个程序,它可以驱动编译器在编译时计算这个总和,并在编译完成时打印结果。

在编译期间打印数字的一个流行技巧是尝试访问模板中不存在的成员,该模板使用您要打印的数字进行实例化:

template<int> struct print_n {};

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

然后编译器会说:

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

有关此技术的更有趣示例,请参阅Solve the eight queens problem at compile-time

【讨论】:

  • 你也可以让print_n保持未定义,看看我的回答。
  • @David 但是高斯需要一个聪明的方法,他没有电脑可以快速地以愚蠢的方式完成它。
【解决方案4】:

由于面试问题中既没有指定编译器也没有指定语言,我敢于使用 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 ...

我们也有一个工作程序。

【讨论】:

    【解决方案5】:

    使用 C++11 会轻松很多,它添加了用于编译时间计算的 constexpr 函数,尽管它们目前仅受 gcc 4.6 或更高版本的支持。

    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,暂时完全忘记了constexpr。也许我只是太喜欢模板了。 :(
    • 这是一个很好的使用 constexpr 来解决问题(参见 Adder 实现):kaizer.se/wiki/log/post/C++_constexpr_foldr
    • 那个公式会溢出;最后一步是/ 2,因此要处理所有可能的unsigned 结果,您右移的值必须是n+1 位宽,但事实并非如此。可以重新排列公式来避免这种情况,就像 clang 对运行时变量范围所做的那样:godbolt.org/z/dUGXqg 表明 clang 知道封闭式公式并使用它来优化 total += i 循环。
    【解决方案6】:

    在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
    

    【讨论】:

      【解决方案7】:

      这是一个在 VC++ 2010 下工作的实现。我不得不将计算分成 3 个阶段,因为当模板递归 500 多次时编译器会报错。

      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 :)
      【解决方案8】:

      我觉得有义务提供这个 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 语言。
      • 你知道有多少个 C 编译器不是 C 的“特定实现”?
      • @Puppy:如果x 是全局的,编译器将(或多或少)需要在编译时评估表达式。 ISO C 不允许全局变量的运行时变量初始值设定项。当然,特定的实现可以发出对类似构造函数的静态初始化函数的调用,该函数在运行时计算并存储。但 ISO C 确实允许您将编译时常量用作数组大小(例如结构定义中的 int y[x]; 或另一个全局变量),因此任何假设的悲观实现仍然必须支持这一点。
      【解决方案9】:

      从 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'
      

      【讨论】:

        【解决方案10】:

        您可以使用(并且主要是滥用)C++ 宏/模板来执行metaprogramming。 AFAIK,Java 不允许做同样的事情。

        【讨论】:

        • 不是这个问题的真正答案。
        • 我认为你是对的。在 java 中,您不能使用相同的模板递归技巧,因为泛型类参数不能是值 - 它必须是类。
        • C# 编译器的泛型特性允许您进行一些编译时计算。请参阅Eric Lippert's post 了解此内容。
        【解决方案11】:

        理论上,你可以这样用:

        #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&lt;500&gt;

        加上一个巨大的伪堆栈跟踪。

        【讨论】:

        • 必须使用标志:-ftemplate-depth-1000
        • @hsalimi:是的。添加标志后,它也适用于 1000。但它不会在编译时打印,并且 Xeo 已经更改了他/她的答案以实际回答这个特定问题,所以我认为我的答案已经过时了。 :-)
        【解决方案12】:

        使用 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;
        }
        

        您可以在 scala using peano numbers 中执行此操作,因为您可以强制编译器进行递归,但我认为您不能在 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
        

        【讨论】:

        • 你没有驱动编译器来compute 500500,对不起。
        • 这是指所有三种解决方案吗?在解决方案 1 中,我获取了一些 java 代码并对其进行编译,编译器打印出 500500。这看起来很像编译器计算 500500。这怎么不是编译器计算 500500?
        • 是的,没错,我在谈论解决方案 2 和 3。我已经在较早的更新中阅读了这个答案,然后又回到了最新的答案,不知何故似乎忘记了第一个解决方案。跨度>
        • 我会说解决方案 2&3 也在计算它。你可以添加任意数量的检查,所以你基本上是在做for (i = 0; i &lt; 100000; ++i) {if (i == 1000*1000/2) print i}。我有一个 160mb 的 java 文件可以做到这一点,它可以工作:)
        【解决方案13】:

        虽然这实际上适用于小数字,但如果我使用 sum_first where N > 400,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;
        }
        

        【讨论】:

          猜你喜欢
          • 2012-10-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-07-20
          相关资源
          最近更新 更多