为两种向量类型或一种向量类型与标量类型之间的二元运算结果确定正确的大小类型
Determine the correct size type for the result of a binary operation between two vector types or one vector type and a scalar type
请考虑以下代码片段:
template<class E>
class vector_expression {};
template<class Tuple>
class vector
: public vector_expression<vector<Tuple>>
{
public:
using value_type = typename Tuple::value_type;
using size_type = typename Tuple::size_type;
};
namespace detail
{
template<class E>
constexpr bool is_vector_expression_v = std::is_base_of_v<vector_expression<std::decay_t<E>>, std::decay_t<E>>;
template<class E, class = void>
struct value_type { using type = std::decay_t<E>; };
template<class E>
struct value_type<E, std::enable_if_t<is_vector_expression_v<E>>> { using type = typename std::decay_t<E>::value_type; };
template<class E>
using value_type_t = typename value_type<E>::type;
template<class E1, class E2, class BinaryOperation>
class vector_binary_operation
{
public:
using value_type = std::result_of_t<BinaryOperation(value_type_t<E1>, value_type_t<E2>)>;
};
}
E1
和 E2
可能是从 vector_expression
派生的类型或用作 vector
.[=36 的 value_type
的任何类型=]
与vector_binary_operation
结果对应的vector
类型需要谨慎选择。它的 value_type
等于调用的结果类型 BinaryOperation
.
是完全合理的
然而,正确的 size_type
更难推断。这是我想要做的:
- 如果
E1
和E2
是vector_expression
,则令size_type = std::conditional_t<
std::numeric_limits<typename std::decay_t<E1>::size_type>::max() <
std::numeric_limits<typename std::decay_t<E2>::size_type>::max(),
typename std::decay_t<E1>::size_type,
typename std::decay_t<E2>::size_type>>>;
- 如果
E1
或E2
(比如E1
)不是vector_expression
,则让size_type = typename std::decay_t<E2>::size_type
不会发生 E1
和 E2
都不是 vector_expression
的情况。但是,(把它当作次要问题)我应该在 vector_binary_operation
的模板参数列表中添加一个 class = std::enable_if_t<is_vector_expression_v<E1> || is_vector_expression_v<E2>>
吗?
主要问题是:如何定义 size_type
如上所述?
一种方法是增加额外的特征或丰富您当前的特征:
您可以创建一个特征,为 vector_expression
提供 sizeof(E1::size_type)
,为
提供 0
template<class E, class = void>
struct value_type {
using type = std::decay_t<E>;
using size_type = char; // or better some dummy type
static constexpr std::size_t size = 0; // To be the minimal size
};
template<class E>
struct value_type<E, std::enable_if_t<is_vector_expression_v<E>>> {
using type = typename std::decay_t<E>::value_type;
using size_type = typename std::decay_t<E>::size_type;
static constexpr std::size_t size = std::numeric_limits<size_type>::max();
};
然后
template<class E1, class E2, class BinaryOperation>
class vector_binary_operation
{
public:
using value_type = std::result_of_t<BinaryOperation(value_type_t<E1>,
value_type_t<E2>)>;
using size_type = std::conditional_t<(value_type<E1>::size < value_type<E2>::size),
typename value_type <E1>::size_type,
typename value_type <E2>::size_type>>>;
};
一般来说,我发现在这种情况下,最简单的方法通常是定义一组重载 auto Foo(E1,E2) -> ResultType
来执行实际操作,然后设置 vector_binary_operation::size_type = decltype(Foo(E1,E2))
。
在您的特定情况下,您将有三个重载:对于 E1、E2 或两者都是 vector_expression。
在这种特殊情况下,我看到了另一种选择。介绍一个专长 template<typename T> class sizer<vector_expression<T>> { const int max = std::numeric_limits<typename std::decay_t<E1>::size_type>::max() ; }
的帮手 template<typename T> class sizer { const int max = 0; }
。
这背后的想法很简单。您的一般表达式比较两个向量表达式的两个属性,并选择 属性 最大的类型。通过将所有其他类型的 属性 定义为零,所有其他类型的排名都低于您的 vector_typs,并且不会被选中。
请考虑以下代码片段:
template<class E>
class vector_expression {};
template<class Tuple>
class vector
: public vector_expression<vector<Tuple>>
{
public:
using value_type = typename Tuple::value_type;
using size_type = typename Tuple::size_type;
};
namespace detail
{
template<class E>
constexpr bool is_vector_expression_v = std::is_base_of_v<vector_expression<std::decay_t<E>>, std::decay_t<E>>;
template<class E, class = void>
struct value_type { using type = std::decay_t<E>; };
template<class E>
struct value_type<E, std::enable_if_t<is_vector_expression_v<E>>> { using type = typename std::decay_t<E>::value_type; };
template<class E>
using value_type_t = typename value_type<E>::type;
template<class E1, class E2, class BinaryOperation>
class vector_binary_operation
{
public:
using value_type = std::result_of_t<BinaryOperation(value_type_t<E1>, value_type_t<E2>)>;
};
}
E1
和 E2
可能是从 vector_expression
派生的类型或用作 vector
.[=36 的 value_type
的任何类型=]
与vector_binary_operation
结果对应的vector
类型需要谨慎选择。它的 value_type
等于调用的结果类型 BinaryOperation
.
然而,正确的 size_type
更难推断。这是我想要做的:
- 如果
E1
和E2
是vector_expression
,则令size_type = std::conditional_t< std::numeric_limits<typename std::decay_t<E1>::size_type>::max() < std::numeric_limits<typename std::decay_t<E2>::size_type>::max(), typename std::decay_t<E1>::size_type, typename std::decay_t<E2>::size_type>>>;
- 如果
E1
或E2
(比如E1
)不是vector_expression
,则让size_type = typename std::decay_t<E2>::size_type
不会发生 E1
和 E2
都不是 vector_expression
的情况。但是,(把它当作次要问题)我应该在 vector_binary_operation
的模板参数列表中添加一个 class = std::enable_if_t<is_vector_expression_v<E1> || is_vector_expression_v<E2>>
吗?
主要问题是:如何定义 size_type
如上所述?
一种方法是增加额外的特征或丰富您当前的特征:
您可以创建一个特征,为 vector_expression
提供 sizeof(E1::size_type)
,为
0
template<class E, class = void>
struct value_type {
using type = std::decay_t<E>;
using size_type = char; // or better some dummy type
static constexpr std::size_t size = 0; // To be the minimal size
};
template<class E>
struct value_type<E, std::enable_if_t<is_vector_expression_v<E>>> {
using type = typename std::decay_t<E>::value_type;
using size_type = typename std::decay_t<E>::size_type;
static constexpr std::size_t size = std::numeric_limits<size_type>::max();
};
然后
template<class E1, class E2, class BinaryOperation>
class vector_binary_operation
{
public:
using value_type = std::result_of_t<BinaryOperation(value_type_t<E1>,
value_type_t<E2>)>;
using size_type = std::conditional_t<(value_type<E1>::size < value_type<E2>::size),
typename value_type <E1>::size_type,
typename value_type <E2>::size_type>>>;
};
一般来说,我发现在这种情况下,最简单的方法通常是定义一组重载 auto Foo(E1,E2) -> ResultType
来执行实际操作,然后设置 vector_binary_operation::size_type = decltype(Foo(E1,E2))
。
在您的特定情况下,您将有三个重载:对于 E1、E2 或两者都是 vector_expression。
在这种特殊情况下,我看到了另一种选择。介绍一个专长 template<typename T> class sizer<vector_expression<T>> { const int max = std::numeric_limits<typename std::decay_t<E1>::size_type>::max() ; }
的帮手 template<typename T> class sizer { const int max = 0; }
。
这背后的想法很简单。您的一般表达式比较两个向量表达式的两个属性,并选择 属性 最大的类型。通过将所有其他类型的 属性 定义为零,所有其他类型的排名都低于您的 vector_typs,并且不会被选中。