Reputation: 123
how would you go about using non-type template parameter comparison in a std::enable_if
?
I can not figure out how to do this again. (I once had this working, but I lost the code so I can't look back on it, and I can't find the post I found the answer in either.)
template<int Width, int Height, typename T>
class Matrix{
static
typename std::enable_if<Width == Height, Matrix<Width, Height, T>>::type
Identity(){
Matrix ret;
for (int y = 0; y < Width; y++){
elements[y][y] = T(1);
}
return ret;
}
}
Edit: Fixed missing bracket as pointed out in comments.
Upvotes: 8
Views: 4137
Reputation: 16242
It all depends on what kind of error/failure you want to raise on invalid code. Here it is one possibility (leaving aside the obvious static_assert(Width==Height, "not square matrix");
)
(C++98 style)
#include<type_traits>
template<int Width, int Height, typename T>
class Matrix{
public:
template<int WDummy = Width, int HDummy = Height>
static typename std::enable_if<WDummy == HDummy, Matrix>::type
Identity(){
Matrix ret;
for (int y = 0; y < Width; y++){
// elements[y][y] = T(1);
}
return ret;
}
};
int main(){
Matrix<5,5,double> m55;
Matrix<4,5,double> m45; // ok
Matrix<5,5, double> id55 = Matrix<5,5, double>::Identity(); // ok
// Matrix<4,5, double> id45 = Matrix<4,5, double>::Identity(); // compilation error!
// and nice error: "no matching function for call to ‘Matrix<4, 5, double>::Identity()"
}
EDIT: In C++11 the code can be more compact and clear, (it works in clang 3.2
but not in gcc 4.7.1
, so I am not sure how standard it is):
(C++11 style)
template<int Width, int Height, typename T>
class Matrix{
public:
template<typename = typename std::enable_if<Width == Height>::type>
static Matrix
Identity(){
Matrix ret;
for(int y = 0; y < Width; y++){
// ret.elements[y][y] = T(1);
}
return ret;
}
};
EDIT 2020: (C++14)
template<int Width, int Height, typename T>
class Matrix{
public:
template<typename = std::enable_if_t<Width == Height>>
static Matrix
Identity()
{
Matrix ret;
for(int y = 0; y < Width; y++){
// ret.elements[y][y] = T(1);
}
return ret;
}
};
(C++20) https://godbolt.org/z/cs1MWj
template<int Width, int Height, typename T>
class Matrix{
public:
static Matrix
Identity()
requires(Width == Height)
{
Matrix ret;
for(int y = 0; y < Width; y++){
// ret.elements[y][y] = T(1);
}
return ret;
}
};
Upvotes: 6
Reputation: 123
I found the answer to my question here: Using C++11 std::enable_if to enable...
In my solution, SFINAE occurs within my templated return type, therefore making the function template in itself valid. In the course of this, the function itself also becomes templated.
template<int Width, int Height, typename T>
class Matrix{
template<typename EnabledType = T>
static
typename Matrix<Width, Height,
typename std::enable_if<Width == Height, EnabledType>::type>
Identity(){
Matrix ret;
for (int y = 0; y < Width; y++){
ret.elements[y][y] = T(1);
}
return ret;
}
}
Upvotes: 1