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.)
Thank you in advance for any help on this topic.
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.
Template non-type arguments in C++It is also possible to use non-type arguments (basic/derived data types) i.e., in addition to the type argument T, it can also use other arguments such as strings, function names, constant expressions, and built-in data types.
There are ways to restrict the types you can use inside a template you write by using specific typedefs inside your template. This will ensure that the compilation of the template specialisation for a type that does not include that particular typedef will fail, so you can selectively support/not support certain types.
A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)
In C++ metaprogramming, std::enable_if is an important function to enable certain types for template specialization via some predicates known at the compile time. Using types that are not enabled by std::enable_if for template specialization will result in compile-time error.
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;
}
};
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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With