除非满足静态条件,否则不要编译转换运算符(Preventing conversion operators from compiling unless a static condition is met)

我有Vector( CVector<T, std::size_t Size> ),Matrix( CMatrix<T, std::size_t Height, std::size_t Width> )和Tensor( CTensor<T, std::size_t... Sizes> )类,如果sizeof...(Sizes) == 1 ,我希望能够从CTensor类隐式转换为CTensor类,如果sizeof...(Sizes) == 2 ,我希望能够隐式转换为CTensor类,所以我有以下转换运算符(最初我没有std::enable_if模板参数希望我可以使用SFINAE来防止它编译):

template <typename std::enable_if<sizeof...(Sizes) == 2, int>::type = 0> operator CMatrix<NumType, Sizes...>() const { static_assert(sizeof...(Sizes) == 2, "You can only convert a rank 2 tensor to a matrix"); CMatrix<NumType, Sizes...> matResult; auto& arrThis = m_numArray; auto& arrResult = matResult.m_numArray; concurrency::parallel_for_each( arrResult.extent, [=, &arrThis, &arrResult]( concurrency::index<2> index ) restrict( amp ) { arrResult[index] = arrThis[index]; } ); return matResult; } template <typename std::enable_if<sizeof...(Sizes) == 1, int>::type = 0> operator CVector<NumType, Sizes...>() const { static_assert(sizeof...(Sizes) == 1, "You can only convert a rank 1 tensor to a vector"); CVector<NumType, Sizes...> vecResult; auto& arrThis = m_numArray; auto& arrResult = vecResult.m_numArray; concurrency::parallel_for_each( arrResult.extent, [=, &arrThis, &arrResult]( concurrency::index<1> index ) restrict( amp ) { arrResult[index] = arrThis[index]; } ); return vecResult; }

但是,如果我实例化CTensor<float, 3, 3, 3>并尝试编译,我将会看到错误,声明CMatrix和CVector模板参数CMatrix以及有关std::enable_if<false, int>缺失类型的错误std::enable_if<false, int> 。 有没有办法实现这些运算符而无需专门针对1级和2级CTensor ?

I have Vector (CVector<T, std::size_t Size>), Matrix (CMatrix<T, std::size_t Height, std::size_t Width>) and Tensor (CTensor<T, std::size_t... Sizes>) classes, and I wish to be able to implicitly convert from a CTensor class to a CVector class if sizeof...(Sizes) == 1 and to a CMatrix class if sizeof...(Sizes) == 2, so I have the following conversion operators (initially I didn't have the std::enable_if template parameter hoping I could use SFINAE to prevent it from compiling):

template <typename std::enable_if<sizeof...(Sizes) == 2, int>::type = 0> operator CMatrix<NumType, Sizes...>() const { static_assert(sizeof...(Sizes) == 2, "You can only convert a rank 2 tensor to a matrix"); CMatrix<NumType, Sizes...> matResult; auto& arrThis = m_numArray; auto& arrResult = matResult.m_numArray; concurrency::parallel_for_each( arrResult.extent, [=, &arrThis, &arrResult]( concurrency::index<2> index ) restrict( amp ) { arrResult[index] = arrThis[index]; } ); return matResult; } template <typename std::enable_if<sizeof...(Sizes) == 1, int>::type = 0> operator CVector<NumType, Sizes...>() const { static_assert(sizeof...(Sizes) == 1, "You can only convert a rank 1 tensor to a vector"); CVector<NumType, Sizes...> vecResult; auto& arrThis = m_numArray; auto& arrResult = vecResult.m_numArray; concurrency::parallel_for_each( arrResult.extent, [=, &arrThis, &arrResult]( concurrency::index<1> index ) restrict( amp ) { arrResult[index] = arrThis[index]; } ); return vecResult; }

However, if I instantiate CTensor<float, 3, 3, 3> for instance, and try to compile, I will be presented with errors declaring that there are too many template parameters for CMatrix and CVector along with errors regarding missing type for std::enable_if<false, int>. Is there a way to implement these operators without having to specialize CTensor for rank 1 and 2?

最满意答案

我简化了以前的解决方案,详情如下。

根本不需要SFINAE,因为模板方法中有static_assert ,只有在使用时才会实例化。

我的解决方案使转换运算符成为具有依赖参数的模板方法(因此编译器不实例化其主体,仅解析签名),并添加-1大小,假装在尺寸1的张量内缺少维度(而不是张量本身,但是对于提取参数包的辅助类,允许编译器实例化张量模板本身,但稍后不允许在无效维度的张量内实例化转换运算符。

现场演示链接。

#include <cstddef> template <typename T, unsigned int index, T In, T... args> struct GetArg { static const T value = GetArg<T, index-1, args...>::value; }; template <typename T, T In, T... args> struct GetArg<T, 0, In, args...> { static const T value = In; }; template <typename T, T In> struct GetArg<T, 1, In> { static const T value = -1; }; template <typename T, std::size_t Size> struct CVector { }; template <typename T, std::size_t Height, std::size_t Width> struct CMatrix { }; template <typename T, std::size_t... Sizes> struct CTensor { template <std::size_t SZ = sizeof...(Sizes)> operator CVector<T, GetArg<std::size_t, 0, Sizes...>::value>() const { static_assert(SZ == 1, "You can only convert a rank 1 tensor to a vector"); CVector<T, Sizes...> vecResult; return vecResult; } template <std::size_t SZ = sizeof...(Sizes)> operator CMatrix<T, GetArg<std::size_t, 0, Sizes...>::value, GetArg<std::size_t, 1, Sizes...>::value>() const { static_assert(SZ == 2, "You can only convert a rank 2 tensor to a matrix"); CMatrix<T, Sizes...> matResult; return matResult; } }; int main() { CTensor<float, 3> tensor3; CTensor<float, 3, 3> tensor3_3; CTensor<float, 3, 3, 3> tensor3_3_3; CVector<float, 3> vec(tensor3); //CVector<float, 3> vec2(tensor3_3); // static_assert fails! CMatrix<float, 3, 3> mat(tensor3_3); //CMatrix<float, 3, 3> mat2(tensor3_3_3); // static_assert fails! }

I have simplified my previous solution, details below.

SFINAE is not needed at all because you have static_assert in template method which is instantiated only upon usage.

My solution makes the conversion operator a template method with dependant argument (so that compiler does not instantiate its body, only parses signature), and adds -1 size that pretends to be missing dimension within tensor of size 1 (not to the tensor itself, but to helper class that extracts parameter pack), to allow compiler instantiate the tensor template itself, but will not allow later on to instantiate the conversion operator within tensor of invalid dimension.

Live demo link.

#include <cstddef> template <typename T, unsigned int index, T In, T... args> struct GetArg { static const T value = GetArg<T, index-1, args...>::value; }; template <typename T, T In, T... args> struct GetArg<T, 0, In, args...> { static const T value = In; }; template <typename T, T In> struct GetArg<T, 1, In> { static const T value = -1; }; template <typename T, std::size_t Size> struct CVector { }; template <typename T, std::size_t Height, std::size_t Width> struct CMatrix { }; template <typename T, std::size_t... Sizes> struct CTensor { template <std::size_t SZ = sizeof...(Sizes)> operator CVector<T, GetArg<std::size_t, 0, Sizes...>::value>() const { static_assert(SZ == 1, "You can only convert a rank 1 tensor to a vector"); CVector<T, Sizes...> vecResult; return vecResult; } template <std::size_t SZ = sizeof...(Sizes)> operator CMatrix<T, GetArg<std::size_t, 0, Sizes...>::value, GetArg<std::size_t, 1, Sizes...>::value>() const { static_assert(SZ == 2, "You can only convert a rank 2 tensor to a matrix"); CMatrix<T, Sizes...> matResult; return matResult; } }; int main() { CTensor<float, 3> tensor3; CTensor<float, 3, 3> tensor3_3; CTensor<float, 3, 3, 3> tensor3_3_3; CVector<float, 3> vec(tensor3); //CVector<float, 3> vec2(tensor3_3); // static_assert fails! CMatrix<float, 3, 3> mat(tensor3_3); //CMatrix<float, 3, 3> mat2(tensor3_3_3); // static_assert fails! }除非满足静态条件,否则不要编译转换运算符(Preventing conversion operators from compiling unless a static condition is met)

我有Vector( CVector<T, std::size_t Size> ),Matrix( CMatrix<T, std::size_t Height, std::size_t Width> )和Tensor( CTensor<T, std::size_t... Sizes> )类,如果sizeof...(Sizes) == 1 ,我希望能够从CTensor类隐式转换为CTensor类,如果sizeof...(Sizes) == 2 ,我希望能够隐式转换为CTensor类,所以我有以下转换运算符(最初我没有std::enable_if模板参数希望我可以使用SFINAE来防止它编译):

template <typename std::enable_if<sizeof...(Sizes) == 2, int>::type = 0> operator CMatrix<NumType, Sizes...>() const { static_assert(sizeof...(Sizes) == 2, "You can only convert a rank 2 tensor to a matrix"); CMatrix<NumType, Sizes...> matResult; auto& arrThis = m_numArray; auto& arrResult = matResult.m_numArray; concurrency::parallel_for_each( arrResult.extent, [=, &arrThis, &arrResult]( concurrency::index<2> index ) restrict( amp ) { arrResult[index] = arrThis[index]; } ); return matResult; } template <typename std::enable_if<sizeof...(Sizes) == 1, int>::type = 0> operator CVector<NumType, Sizes...>() const { static_assert(sizeof...(Sizes) == 1, "You can only convert a rank 1 tensor to a vector"); CVector<NumType, Sizes...> vecResult; auto& arrThis = m_numArray; auto& arrResult = vecResult.m_numArray; concurrency::parallel_for_each( arrResult.extent, [=, &arrThis, &arrResult]( concurrency::index<1> index ) restrict( amp ) { arrResult[index] = arrThis[index]; } ); return vecResult; }

但是,如果我实例化CTensor<float, 3, 3, 3>并尝试编译,我将会看到错误,声明CMatrix和CVector模板参数CMatrix以及有关std::enable_if<false, int>缺失类型的错误std::enable_if<false, int> 。 有没有办法实现这些运算符而无需专门针对1级和2级CTensor ?

I have Vector (CVector<T, std::size_t Size>), Matrix (CMatrix<T, std::size_t Height, std::size_t Width>) and Tensor (CTensor<T, std::size_t... Sizes>) classes, and I wish to be able to implicitly convert from a CTensor class to a CVector class if sizeof...(Sizes) == 1 and to a CMatrix class if sizeof...(Sizes) == 2, so I have the following conversion operators (initially I didn't have the std::enable_if template parameter hoping I could use SFINAE to prevent it from compiling):

template <typename std::enable_if<sizeof...(Sizes) == 2, int>::type = 0> operator CMatrix<NumType, Sizes...>() const { static_assert(sizeof...(Sizes) == 2, "You can only convert a rank 2 tensor to a matrix"); CMatrix<NumType, Sizes...> matResult; auto& arrThis = m_numArray; auto& arrResult = matResult.m_numArray; concurrency::parallel_for_each( arrResult.extent, [=, &arrThis, &arrResult]( concurrency::index<2> index ) restrict( amp ) { arrResult[index] = arrThis[index]; } ); return matResult; } template <typename std::enable_if<sizeof...(Sizes) == 1, int>::type = 0> operator CVector<NumType, Sizes...>() const { static_assert(sizeof...(Sizes) == 1, "You can only convert a rank 1 tensor to a vector"); CVector<NumType, Sizes...> vecResult; auto& arrThis = m_numArray; auto& arrResult = vecResult.m_numArray; concurrency::parallel_for_each( arrResult.extent, [=, &arrThis, &arrResult]( concurrency::index<1> index ) restrict( amp ) { arrResult[index] = arrThis[index]; } ); return vecResult; }

However, if I instantiate CTensor<float, 3, 3, 3> for instance, and try to compile, I will be presented with errors declaring that there are too many template parameters for CMatrix and CVector along with errors regarding missing type for std::enable_if<false, int>. Is there a way to implement these operators without having to specialize CTensor for rank 1 and 2?

最满意答案

我简化了以前的解决方案,详情如下。

根本不需要SFINAE,因为模板方法中有static_assert ,只有在使用时才会实例化。

我的解决方案使转换运算符成为具有依赖参数的模板方法(因此编译器不实例化其主体,仅解析签名),并添加-1大小,假装在尺寸1的张量内缺少维度(而不是张量本身,但是对于提取参数包的辅助类,允许编译器实例化张量模板本身,但稍后不允许在无效维度的张量内实例化转换运算符。

现场演示链接。

#include <cstddef> template <typename T, unsigned int index, T In, T... args> struct GetArg { static const T value = GetArg<T, index-1, args...>::value; }; template <typename T, T In, T... args> struct GetArg<T, 0, In, args...> { static const T value = In; }; template <typename T, T In> struct GetArg<T, 1, In> { static const T value = -1; }; template <typename T, std::size_t Size> struct CVector { }; template <typename T, std::size_t Height, std::size_t Width> struct CMatrix { }; template <typename T, std::size_t... Sizes> struct CTensor { template <std::size_t SZ = sizeof...(Sizes)> operator CVector<T, GetArg<std::size_t, 0, Sizes...>::value>() const { static_assert(SZ == 1, "You can only convert a rank 1 tensor to a vector"); CVector<T, Sizes...> vecResult; return vecResult; } template <std::size_t SZ = sizeof...(Sizes)> operator CMatrix<T, GetArg<std::size_t, 0, Sizes...>::value, GetArg<std::size_t, 1, Sizes...>::value>() const { static_assert(SZ == 2, "You can only convert a rank 2 tensor to a matrix"); CMatrix<T, Sizes...> matResult; return matResult; } }; int main() { CTensor<float, 3> tensor3; CTensor<float, 3, 3> tensor3_3; CTensor<float, 3, 3, 3> tensor3_3_3; CVector<float, 3> vec(tensor3); //CVector<float, 3> vec2(tensor3_3); // static_assert fails! CMatrix<float, 3, 3> mat(tensor3_3); //CMatrix<float, 3, 3> mat2(tensor3_3_3); // static_assert fails! }

I have simplified my previous solution, details below.

SFINAE is not needed at all because you have static_assert in template method which is instantiated only upon usage.

My solution makes the conversion operator a template method with dependant argument (so that compiler does not instantiate its body, only parses signature), and adds -1 size that pretends to be missing dimension within tensor of size 1 (not to the tensor itself, but to helper class that extracts parameter pack), to allow compiler instantiate the tensor template itself, but will not allow later on to instantiate the conversion operator within tensor of invalid dimension.

Live demo link.

#include <cstddef> template <typename T, unsigned int index, T In, T... args> struct GetArg { static const T value = GetArg<T, index-1, args...>::value; }; template <typename T, T In, T... args> struct GetArg<T, 0, In, args...> { static const T value = In; }; template <typename T, T In> struct GetArg<T, 1, In> { static const T value = -1; }; template <typename T, std::size_t Size> struct CVector { }; template <typename T, std::size_t Height, std::size_t Width> struct CMatrix { }; template <typename T, std::size_t... Sizes> struct CTensor { template <std::size_t SZ = sizeof...(Sizes)> operator CVector<T, GetArg<std::size_t, 0, Sizes...>::value>() const { static_assert(SZ == 1, "You can only convert a rank 1 tensor to a vector"); CVector<T, Sizes...> vecResult; return vecResult; } template <std::size_t SZ = sizeof...(Sizes)> operator CMatrix<T, GetArg<std::size_t, 0, Sizes...>::value, GetArg<std::size_t, 1, Sizes...>::value>() const { static_assert(SZ == 2, "You can only convert a rank 2 tensor to a matrix"); CMatrix<T, Sizes...> matResult; return matResult; } }; int main() { CTensor<float, 3> tensor3; CTensor<float, 3, 3> tensor3_3; CTensor<float, 3, 3, 3> tensor3_3_3; CVector<float, 3> vec(tensor3); //CVector<float, 3> vec2(tensor3_3); // static_assert fails! CMatrix<float, 3, 3> mat(tensor3_3); //CMatrix<float, 3, 3> mat2(tensor3_3_3); // static_assert fails! }