Re: Recursive template instantiation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 31 March 2014 13:07, Yury Usishchev wrote:
> Hello!
>
> I have a question about test case in pr60687:
>
> template <typename CALLER>
> void exec1(CALLER & caller) {
>   struct Me : public CALLER {
>   public:
>     Me(CALLER & caller) : CALLER(caller) {};
>     void exec() {
>       if(0) exec1(*this);
>     }
>   } me(caller);
>   return me.exec();
> }
>
> int main(int, char**) {
>   struct Me0 {} me;
>   exec1(me);
>   return 0;
> }
>
> Currently gcc fails to compile it with 'template
> instantiation depth exceeds maximum' error
>
> But actually exec1 is not recursive, so we dont need
> to instantiate all these templates.
>
> So the question is:
>   Is this behavior valid? Or maybe according to C++11
> standard we should be able to compile and run such code.

I'm pretty sure what G++ is doing is allowed by the standard. The code
above is only non-recursive because of the if(0) condition, but the
exec1(*this) call still has to be calid C++, and to compile that
statement the compiler has to do overload resolution, which means
instantiating the function template that would be called.

The standard does not require compilers to do dead code elimination
and remove the statement following the condition, that's an
optimisation, not a requirement of the language. Even if it was
required the eliminated call would still have to be valid C++ and so
would require template instantiation, and that recursively
instantiates the next function template and so on.

Because the code above depends on a constant you could terminate the
recursion quite easily by overloading the function and dispatching on
the value of that constant:

#include <type_traits>

template <typename CALLER>
void exec1(CALLER & caller, std::integral_constant<int, 0>) {
}

template <typename CALLER, int N = 1>
void exec1(CALLER & caller, std::integral_constant<int, N> = {}) {
  struct Me : public CALLER {
  public:
    Me(CALLER & caller) : CALLER(caller) {};
    void exec() {
      exec1(*this, std::integral_constant<int, 0>());
    }
  } me(caller);
  return me.exec();
}

int main(int, char**) {
  struct Me0 {} me;
  exec1(me);
  return 0;
}

For the original testcase in the bug report I don't think that's
possible, because the condition is a run-time value not a constant. In
that case it should be obvious that the compiler cannot easily prove
the recursion terminates without performing some non-trivial
optimisations, but those optimisations don't happen until after
template instantiation has been completed.




[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux