I'am writing a simple class with some member functions as usual, and this time I'am trying to define a member function only when the template parameters of the class meet some conditions, but the codes seems unable to be compiled in both g++ and vs2019. The simplest demo is like this:
#include <type_traits>
template <int RowCnt, int ColCnt, typename ValueType = double>
class Matrix {
public:
template <std::enable_if_t<RowCnt == ColCnt, int> = 0>
void GetInverseMatrix() {}
private:
ValueType data[RowCnt][ColCnt];
};
int main() {
Matrix<3, 3> a;
Matrix<3, 5> b; // Compilation would fail here
return 0;
}
Error outputs from g++ are like this:
test_enable_if_valid.cc: In instantiation of ‘class Matrix<3, 5>’:
test_enable_if_valid.cc:15:16: required from here
test_enable_if_valid.cc:7:8: error: no type named ‘type’ in ‘struct std::enable_if<false, int>’
7 | void GetInverseMatrix() {}
|
While vs2019 told similar things:
1>D:\labs\enable_if_test_1\main.cpp(7,1): error C2938: 'std::enable_if_t<false,int>' : Failed to specialize alias template
1>D:\labs\enable_if_test_1\main.cpp(6,17): message : see reference to alias template instantiation 'std::enable_if_t<false,int>' being compiled
1>D:\labs\enable_if_test_1\main.cpp(15,15): message : see reference to class template instantiation 'Matrix<3,5,double>' being compiled
In my opinion, compilers could have skipped the compilation of GetInverseMatrix() function because there are no calls for Matrix<3, 5>::GetInverseMatrix(), or unless the SFINA rules should work. Could you please tell me why I am wrong or why compilers behave differently from my expectation above?
Thank you in advance, and any information would be appreciated!
SFINAE works when substituting the explicitly specified or deduced template argument for the template parameter.
The function template
GetInverseMatrixhas one template parameter, and the parameter itself is invalid unlessRowCnt == ColCnt, before any substitution even takes place.Validity of a template parameter may depend on a preceding template parameter of that same template, so this is OK:
But this is not OK:
A function template that is not called is not instantiated, but any function template must have at least a valid template parameter list.
One way to write this template would be