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.
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.