我有一个模板矩阵类,例如(简化形式):
template<typename Scalar, typename Accessor = GenericAccessor>
class Matrix {
public:
Matrix(size_t num_rows, size_t num_cols, const std::vector<Scalar>& elems)
: num_rows_(num_rows), num_cols_(num_cols),
accessor_(num_rows, num_cols),
storage_(elems) {}
private:
size_t num_rows_;
size_t num_cols_;
Accessor accessor_;
std::vector<Scalar> storage_;
}
这个类有 Transpose
方法,它将返回一个新的矩阵,其中行和列交换了和不同的访问器类型。
我当前的实现似乎不起作用,因为我尝试返回不同专业化的矩阵:
Matrix Transpose() {
if (dynamic_cast<TransposeAccessor*>(accessor_)) {
return Matrix<Scalar, GenericAccessor>(num_cols_, num_rows_, storage_);
}
return Matrix<Scalar, TransposeAccessor>(num_cols_, num_rows_, storage_);
}
我知道返回类型应该匹配类特化,但是我该如何正确实现 Transpose
方法呢?
答案 0 :(得分:2)
'Matrix' 在这里指的是当前上下文,即您声明了返回一种类型的函数,而您试图返回两种不同的类型。我假设它们没有关系。您必须静态地执行选择,即具有两个单独的“转置”专业化。如果访问器可以动态改变,那么你必须做一些类型擦除。
这是出于“疯狂的想法”,可能不应该遵循。
#include <iostream>
#include <concepts>
struct GenericAccesstor {};
struct TransposeAccesstor {};
template<typename T>
concept GenericAccess = requires(T a) {
{a} -> std::convertible_to<GenericAccesstor>;
};
template<typename T>
concept TransposedAcccess = requires(T a) {
{a} -> std::convertible_to<TransposeAccesstor>;
};
template < typename Scalar, typename Accessor = GenericAccesstor >
struct Matrix {
using access_type = Accessor;
template < GenericAccess A = Accessor >
auto Transpose() -> Matrix<Scalar, TransposeAccesstor >
{ return Matrix<Scalar, TransposeAccesstor>(); }
template < TransposedAcccess A = Accessor >
auto Transpose() -> Matrix<Scalar, GenericAccesstor >
{ return Matrix<Scalar, GenericAccesstor>(); }
};
我们可以检查它是如何工作的:
int main()
{
Matrix<int, GenericAccesstor> m;
auto m2 = m.Transpose();
auto m3 = m2.Transpose();
std::cout << typeid(decltype(m)::access_type).name() << std::endl;
std::cout << typeid(decltype(m2)::access_type).name() << std::endl;
std::cout << typeid(decltype(m3)::access_type).name() << std::endl;
}
/** Output:
16GenericAccesstor
18TransposeAccesstor
16GenericAccesstor */
Tbh,我根本不会以这种方式构建 Matrix,因为听起来转置矩阵是一种与原始矩阵不同的类型,所以我不确定完全实现的好坏。
答案 1 :(得分:2)
如果我正确理解您的问题,您想返回 Matrix<Scalar, TransposeAccessor >
if Accessor = GenericAcessor
反之亦然。
一种方法是创建一个辅助类模板,它允许您通过专门化模板来为您的访问器获取相反类型(您可能需要选择一个更好的名称):< /p>
template<typename T>
struct accessor_trait;
template<>
struct accessor_trait<GenericAcessor> {
using oppsite_type = TransposeAccessor;
};
template<>
struct accessor_trait<TransposeAccessor> {
using oppsite_type = GenericAcessor;
};
然后您的 Transpose
函数可能如下所示:
auto Transpose() {
return Matrix<Scalar, typename accessor_trait<Accessor>::oppsite_type>(num_cols_, num_rows_, storage_);
}
如果您需要在不同的地方使用 oppsite 访问器,您可能希望这样编写:
template<typename Scalar, typename Accessor = GenericAcessor>
class Matrix {
public:
// create a name alias here to be used at other places
using OppsiteAccessor = Matrix<Scalar, typename acessor_trait<Accessor>::oppsite_type>;
Matrix(std::size_t num_rows, std::size_t num_cols, const std::vector<Scalar>& elems)
: num_rows_(num_rows), num_cols_(num_cols),
accessor_(num_rows, num_cols),
storage_(elems) {}
Matrix<Scalar, OppsiteAccessor> Transpose() {
return Matrix<Scalar, OppsiteAccessor>(num_cols_, num_rows_, storage_);
}
private:
std::size_t num_rows_;
std::size_t num_cols_;
Accessor accessor_;
std::vector<Scalar> storage_;
};
答案 2 :(得分:1)
auto Transpose() {
if constexpr (std::is_same_v<TransposeAccessor,decltype(accessor_)>) {
return Matrix<Scalar, GenericAccessor>(num_cols_, num_rows_, storage_);
} else {
return Matrix<Scalar, TransposeAccessor>(num_cols_, num_rows_, storage_);
}
}