C ++ template functions optimization failure

In my opinion, a branch that evaluates to false at compile time will not be accepted. In the following code, the compiler should not discard the block containing the line causing the error?

#include <iostream>

template<int i1, int i2>
void TemplateFunc()
{
    std::cout << i1 << std::endl;
    if(i2 > 0)
    {
        std::cout << i2 << std::endl;
        // The following causes an error
        // "cannot allocate an array of constant size 0"
        int someThing[i2] = {276};
        std::cout << someThing[i2/2] << std::endl;
    }
}

int main(int argc, char** argv)
{
    TemplateFunc<1,2>();
    TemplateFunc<3,0>();
    return 0;
}

      

I tried this with VS 2012, g ++ (on coliru with "g ++ -std = c ++ 11 -O3 -Wall -pedantic -pthread main.cpp &. / A.out") and using nvcc (with similar code in cuda core ).

+3


source to share


2 answers


Templates only confuse questions. Let's look at a simpler example.

int main() {
  if (0) {
    int array[0];
  }
}

      

This leads to compile-time diagnostics (if implemented accordingly). According to your logic, it shouldn't, because the block is if

never taken.

In theory it is checked to see if it is 0

zero at runtime, so the compiler should consider the possibility that a branch might be committed.



In practice, compilers optimize constant conditions, but according to the as-if rule, which effectively states that optimization should not change the meaning of the program. An unoptimized program will have an error that will be diagnosed at compile time. Therefore, the optimized program still has an error that is diagnosed at compile time.

There are several ways to enable checks to be performed at compile time. One method is to partially specialize the template and remove the offending code from the specialization, which would be attempted if i2

not positive:

template<int i1, int i2, bool i2_is_positive>
struct TemplateFuncImpl;

template<int i1, int i2>
struct TemplateFuncImpl<i1, i2, false> {
  static void Impl() {
    std::cout << i1 << std::endl;
  }
};

template<int i1, int i2>
struct TemplateFuncImpl<i1, i2, true> {
  static void Impl() {
    std::cout << i1 << std::endl;
    std::cout << i2 << std::endl;
    int someThing[i2] = {276};
    std::cout << someThing[i2/2] << std::endl;
  }
};

template<int i1, int i2>
void TemplateFunc()
{
    TemplateFuncImpl<i1, i2, (i2 > 0)>::Impl();
}

      

This is admittedly very verbose, so it might not be what you really want to use. Unfortunately there is no easy method. @Columbo mentions that there have been suggestions for a variant of an instruction if

that would be forced to run at compile time, but nothing that actually made it a standard.

+2


source


I think you misunderstood how the compiler works. Creation of a template may be denied, but if the compiler is going to instantiate the template, it must compile first. Since it doesn't compile and there are no alternative patterns to use, it will fail with a compilation error.

If it were a templating class, you could make this possible with partial specialization:



#include <iostream>

template<int i1, int i2>
class TemplateFunc {
public:
  void operator()() {
    ...code with an if...
  }
};

template<int i1>
class TemplateFunc<i1, 0> {
public:
  void operator()() {
    ...code without and if...
  }
};

int main(int argc, char** argv)  
{
  TemplateFunc<1,2>()();
  TemplateFunc<3,0>()();
  return 0;
}

      

In this code, the if template will not be selected by the compiler due to specialization, and therefore no compilation error will occur. But for functions, this method is simply not allowed by today's standards.

+3


source







All Articles