Search code examples
c++c++11templatesconstexpricc

Constexpr as Array Size in Template Function (GCC vs Intel)


I'm working on a scientific code written in C++11. The crucial operations of this code are performed on 3D-arrays. Such arrays are also passed around to other functions a lot. While implementing some new features I used templates and ran into the following Problem: The code compiles fine with gcc 5.4 (also tested 7.2) but with the Intel C++ compiler ICC 16.0 (also tested 18.0) it does not compile, so I wonder whether my code is not standard compliant or if one of those compilers is misbehaving.

A minimal example code looks as follows (in reality it would be 3D-arrays):

class Constants {   
   static constexpr int value_ = 2;

public:    
   static constexpr inline int V() { return value_; }    
};

typedef Constants CC;

template<int N>
class Terror {    
public:
  template<class T>
  void F(T (&a)[CC::V()]) {}
};

int main() {
  int array[CC::V()];    
  Terror<42> ter = Terror<42>();    
  ter.F(array);
}

I know that passing a (3D) plain C Array, with sizes determined via constexpr, is not the classical approach, but there are reasons for this on which I can elaborate if desired.

I tried reading through the C++11 standard but did not find a clear (at least to me) description to my problem.

The error ICC is throwing is this:

main.cpp(15): error: no instance of function template "Terror<N>::F [with N=42]" matches the argument list
            argument types are: (int [2])
            object type is: Terror<42>
   ter.F(array); 
       ^
template_class.h(10): note: this candidate was rejected because at least one template argument could not be deduced
    void F(T (&a)[CC::V()]) {}
         ^

compilation aborted for main.cpp (code 2)

Interestingly, it works with (3D-)std::array or if one of the two templates N/T is is not existing.


Solution

  • This is an ICC bug.

    Thankfully, there's a very simple workaround which is just storing that value within Terror:

    template<int N>
    class Terror {    
        static constexpr size_t M = CC::V();
    public:
        template<class T>
        void F(T (&a)[M]) {}
    };
    

    ICC 16 and 17 both accept your program with this change.