C++ 部分模板专业化问题
C++ partial template specialization issue
给定一个矩阵class
using index_t = int;
template<index_t M, index_t N, typename S>
struct mat {
// matrix implementation
};
我想要一种获取给定类型 T
的 elementCount 的通用方法,该方法适用于矩阵和标量。例如,我想象能够做到这一点:
dimensionality<mat<1,2,double>>(); // returns 2
dimensionality<mat<2,2,float>>(); // returns 4
dimensionality<double>(); // returns 1
或者可能是这样的:
attributes<mat<1,2,double>>::dimensionality; // returns 2
attributes<mat<2,2,float>>::dimensionality; // returns 4
attributes<double>::dimensionality; // returns 1
我的尝试:
我尝试执行以下操作(认为我部分专注于 struct attributes
):
template<typename T>
struct attributes {};
template<typename S, typename = std::enable_if_t<std::is_arithmetic<S>::value>>
struct attributes<S> { // <--- compiler error on this line
static constexpr index_t dimensionality = 1;
};
template<index_t M, index_t N, typename S>
struct attributes<mat<M, N, S>> {
static constexpr index_t dimensionality = M * N;
};
但我在指示的行上收到编译器错误。你能帮助我吗(建议更好的方法,或者了解我做错了什么)?
您可以添加另一个默认类型为 void
的模板参数,然后将 std::enable_if
指定为算术类型偏特化中相应的模板参数。 (并调整 mat
的偏特化。)
template<typename T, typename = void>
struct attributes {};
template<typename S>
struct attributes<S, std::enable_if_t<std::is_arithmetic<S>::value>> {
static constexpr index_t dimensionality = 1;
};
template<index_t M, index_t N, typename S>
struct attributes<mat<M, N, S>, void> {
static constexpr index_t dimensionality = M * N;
};
首先,特化的模板参数不能多于主模板,但您的代码为算术情况设置了 typename = std::enable_if_t
。
其次,为了使这个 std::enable_if_t
起作用,它需要产生使专业化比主模板更专业的东西,而不仅仅是有效的。为此,您可以使用 void_t
技巧:
template <typename T, typename = void>
struct attributes {};
template <typename S>
struct attributes<S, std::enable_if_t<std::is_arithmetic<S>::value>> {
static constexpr index_t dimensionality = 1;
};
这也意味着矩阵的特化也应该包括这个 void
参数:
template <index_t M, index_t N, typename S>
struct attributes<mat<M, N, S>, void> {
static constexpr index_t dimensionality = M * N;
};
但是,您的特征可以缩短为:
template <typename T>
struct attributes {
static_assert(std::is_arithmetic<T>::value, "T must be arithmetic or mat");
static constexpr index_t dimensionality = 1;
};
template <index_t M, index_t N, typename S>
struct attributes<mat<M, N, S>> {
static constexpr index_t dimensionality = M * N;
};
也就是说,当没有专业化匹配时,只考虑主模板中的算术类型。
包装一个基于特征的静态常量:std::integral_constant
您可能想利用 std::integral_constant
from <type_traits>
来实现您的特质,
[...] std::integral_constant
wraps a static constant of specified type. It is the base class for the C++ type traits.
并提供辅助变量模板 dimensionality_v
以便于使用:
#include <type_traits>
// Default dimensionality 0.
template <class T, typename = void>
struct dimensionality : std::integral_constant<index_t, 0> {};
template <typename S>
struct dimensionality<S, std::enable_if_t<std::is_arithmetic_v<S>>>
: std::integral_constant<index_t, 1> {};
template <index_t M, index_t N, typename S>
struct dimensionality<mat<M, N, S>> : std::integral_constant<index_t, M * N> {};
template <class T>
inline constexpr index_t dimensionality_v = dimensionality<T>::value;
DEMO.
或者,如果您不想为既不满足 std::is_arithmetic_v
也不等于 mat
的类型允许默认维度:
template <class T, typename = void>
struct dimensionality {};
template <typename S>
struct dimensionality<S, std::enable_if_t<std::is_arithmetic_v<S>>>
: std::integral_constant<index_t, 1> {};
template <index_t M, index_t N, typename S>
struct dimensionality<mat<M, N, S>> : std::integral_constant<index_t, M * N> {};
template <class T>
inline constexpr index_t dimensionality_v = dimensionality<T>::value;
DEMO.
给定一个矩阵class
using index_t = int;
template<index_t M, index_t N, typename S>
struct mat {
// matrix implementation
};
我想要一种获取给定类型 T
的 elementCount 的通用方法,该方法适用于矩阵和标量。例如,我想象能够做到这一点:
dimensionality<mat<1,2,double>>(); // returns 2
dimensionality<mat<2,2,float>>(); // returns 4
dimensionality<double>(); // returns 1
或者可能是这样的:
attributes<mat<1,2,double>>::dimensionality; // returns 2
attributes<mat<2,2,float>>::dimensionality; // returns 4
attributes<double>::dimensionality; // returns 1
我的尝试:
我尝试执行以下操作(认为我部分专注于 struct attributes
):
template<typename T>
struct attributes {};
template<typename S, typename = std::enable_if_t<std::is_arithmetic<S>::value>>
struct attributes<S> { // <--- compiler error on this line
static constexpr index_t dimensionality = 1;
};
template<index_t M, index_t N, typename S>
struct attributes<mat<M, N, S>> {
static constexpr index_t dimensionality = M * N;
};
但我在指示的行上收到编译器错误。你能帮助我吗(建议更好的方法,或者了解我做错了什么)?
您可以添加另一个默认类型为 void
的模板参数,然后将 std::enable_if
指定为算术类型偏特化中相应的模板参数。 (并调整 mat
的偏特化。)
template<typename T, typename = void>
struct attributes {};
template<typename S>
struct attributes<S, std::enable_if_t<std::is_arithmetic<S>::value>> {
static constexpr index_t dimensionality = 1;
};
template<index_t M, index_t N, typename S>
struct attributes<mat<M, N, S>, void> {
static constexpr index_t dimensionality = M * N;
};
首先,特化的模板参数不能多于主模板,但您的代码为算术情况设置了 typename = std::enable_if_t
。
其次,为了使这个 std::enable_if_t
起作用,它需要产生使专业化比主模板更专业的东西,而不仅仅是有效的。为此,您可以使用 void_t
技巧:
template <typename T, typename = void>
struct attributes {};
template <typename S>
struct attributes<S, std::enable_if_t<std::is_arithmetic<S>::value>> {
static constexpr index_t dimensionality = 1;
};
这也意味着矩阵的特化也应该包括这个 void
参数:
template <index_t M, index_t N, typename S>
struct attributes<mat<M, N, S>, void> {
static constexpr index_t dimensionality = M * N;
};
但是,您的特征可以缩短为:
template <typename T>
struct attributes {
static_assert(std::is_arithmetic<T>::value, "T must be arithmetic or mat");
static constexpr index_t dimensionality = 1;
};
template <index_t M, index_t N, typename S>
struct attributes<mat<M, N, S>> {
static constexpr index_t dimensionality = M * N;
};
也就是说,当没有专业化匹配时,只考虑主模板中的算术类型。
包装一个基于特征的静态常量:std::integral_constant
您可能想利用 std::integral_constant
from <type_traits>
来实现您的特质,
[...]
std::integral_constant
wraps a static constant of specified type. It is the base class for the C++ type traits.
并提供辅助变量模板 dimensionality_v
以便于使用:
#include <type_traits>
// Default dimensionality 0.
template <class T, typename = void>
struct dimensionality : std::integral_constant<index_t, 0> {};
template <typename S>
struct dimensionality<S, std::enable_if_t<std::is_arithmetic_v<S>>>
: std::integral_constant<index_t, 1> {};
template <index_t M, index_t N, typename S>
struct dimensionality<mat<M, N, S>> : std::integral_constant<index_t, M * N> {};
template <class T>
inline constexpr index_t dimensionality_v = dimensionality<T>::value;
DEMO.
或者,如果您不想为既不满足 std::is_arithmetic_v
也不等于 mat
的类型允许默认维度:
template <class T, typename = void>
struct dimensionality {};
template <typename S>
struct dimensionality<S, std::enable_if_t<std::is_arithmetic_v<S>>>
: std::integral_constant<index_t, 1> {};
template <index_t M, index_t N, typename S>
struct dimensionality<mat<M, N, S>> : std::integral_constant<index_t, M * N> {};
template <class T>
inline constexpr index_t dimensionality_v = dimensionality<T>::value;
DEMO.