gpt4 book ai didi

C++ Matrix模板,矩阵矩阵和矩阵数字乘法之间的歧义

转载 作者:行者123 更新时间:2023-11-28 00:39:56 38 4
gpt4 key购买 nike

我正在写一个矩阵模板类。一切顺利,直到我重载乘法运算符。我的类(class)看起来像这样:

template <typename TNum> class Matrix
{
private:
// ...
TNum* Data;
public:
const TMatIdx NRows; // Type TMatIdx defined somewhere else.
const TMatIdx NCols;
const TMatIdx Size;

// ...
// Matrix * matrix
template <typename T2>
const Matrix<TNum> operator*(const Matrix<T2>& right) const;

// Matrix * number
template <typename T2>
Matrix<TNum>& operator*=(const T2& scale);
};

// Matrix * number
template <typename TNum, typename T2>
Matrix<TNum> operator*(Matrix<TNum> lhs, const T2& rhs);
// Number * matrix
template <typename TNum, typename T2>
Matrix<TNum> operator*(const T2& lhs, Matrix<TNum> rhs);

我希望用相同的 * 涵盖矩阵和数字之间所有可能的乘法组合运营商。

然后我写了一个小测试程序,将两个 Matrix<double> 相乘s,我的 clang++ 编译器提示歧义:

test.cpp:46: error: ambiguous overload for 'operator*' in 'M * N'
matrix.h:225: note: candidates are: const QCD::Matrix<TNum> QCD::Matrix<TNum>::operator*(const QCD::Matrix<T2>&) const [with T2 = double, TNum = double]
matrix.h:118: note: QCD::Matrix<TNum> QCD::operator*(const T2&, QCD::Matrix<TNum>) [with TNum = double, T2 = QCD::Matrix<double>]
matrix.h:109: note: QCD::Matrix<TNum> QCD::operator*(QCD::Matrix<TNum>, const T2&) [with TNum = double, T2 = QCD::Matrix<double>]
test.cpp:52: error: ambiguous overload for 'operator*' in 'M * N'
matrix.h:225: note: candidates are: const QCD::Matrix<TNum> QCD::Matrix<TNum>::operator*(const QCD::Matrix<T2>&) const [with T2 = double, TNum = double]
matrix.h:118: note: QCD::Matrix<TNum> QCD::operator*(const T2&, QCD::Matrix<TNum>) [with TNum = double, T2 = QCD::Matrix<double>]
matrix.h:109: note: QCD::Matrix<TNum> QCD::operator*(QCD::Matrix<TNum>, const T2&) [with TNum = double, T2 = QCD::Matrix<double>]

是否可以在不必明确写下 T2 的所有可能特化的情况下克服这种歧义?

仅供引用,这是我的实现:

template<typename TNum> template <typename T2>
Matrix<TNum>& Matrix<TNum> ::
operator*=(const T2& rhs)
{
for(TMatIdx i = 0; i < Size; i++)
Data[i] *= rhs;
return *this;
}

template<typename TNum> template <typename T2>
const Matrix<TNum> Matrix<TNum> ::
operator*(const Matrix<T2>& right) const
{
Matrix<TNum> c(NRows, right.NCols);
TNum sum_elems;
for(TMatIdx i = 0; i < NRows; i++)
{
for(TMatIdx j = 0; j < right.NCols; j++)
{
sum_elems = TNum(0);
for(TMatIdx k = 0; k < right.NRows; k++)
{
sum_elems += at(i, k) * right.at(k, j);
}

c.at(i, j) = sum_elems;
}
}
return c;
}


template <typename TNum, typename T2>
Matrix<TNum> operator*(Matrix<TNum> lhs, const T2& rhs)
{
lhs *= rhs;
return lhs;
}

template <typename TNum, typename T2>
Matrix<TNum> operator*(const T2& lhs, Matrix<TNum> rhs)
{
rhs *= lhs;
return rhs;
}

最佳答案

我将描述一个使用 c++11 的解决方案,然后解释如何在 c++98 中实现它。

在 c++11 中, header <type_traits>包括类型函数和类型谓词。这使得强制约束更加方便。

std::is_same<T1, T2>::value如果 T1 为真与 T2 的类型相同否则为假。

typename std::enable_if< bool, T >::type是一个定义明确的类型 T如果 bool 为真,否则定义错误。

当编译器寻找候选模板函数和方法时,如果尝试的特化失败,它不会抛出错误。它只是抛出了那个候选人。这意味着以下代码将消除歧义:

template <typename TNum, typename T2>
typename std::enable_if< (!std::is_same<Matrix<TNum>, T2>::value),
Matrix<TNum> >::type operator*(const T2& lhs, Matrix<TNum> rhs);

做出此决定时只考虑声明。上述逻辑在语义上是合理的,但读起来很碍眼。所以 c++11 支持模板别名和 constexpr 函数。

template<bool B, typename T = void>
using Enable_if = typename std::enable_if<B, T>::type;

template<typename T1, typename T2>
constexpr bool Is_same(){
return std::is_same<T1, T2>::value;
}

然后上面变成:

template <typename TNum, typename T2>
Enable_if<( !Is_same<Matrix<TNum>, T2>() ),
Matrix<TNum> > operator*(const T2& lhs, Matrix<TNum> rhs);

概念将提供使这更方便的工具。

现在,如果您没有 c++11,您就不会得到吸引眼球的东西。但是,Boost 提供了相同的功能。假设您两者都没有,实现它们并不可怕。

编译时函数依赖于多种语言规则,这使得它们难以理解。我们会考虑 enable_if第一的。我们要typename enable_if<true, T>::type定义明确但是,typename enable_if<false, T>::type胡说八道。我们使用特化:

template<bool B, typename T = void>
struct enable_if {
typedef T type;
};

template<typename T>
struct enable_if<false, T> {};

注意 false 恰好处理了一半的相关案例。上面的内容值得细细品味。

为了实现is_same ,我们在编译时需要一个 true 或 false 的概念。我们可以用静态常量变量来保证这一点。我们要is_same只要它的模板参数相同,就有一个编译时真值。特化系统规则直接处理这个问题。

template<typename, typename>
struct is_same{
static const bool value = false;
};

template<typename T>
struct is_same<T, T>{
static const bool value = true;
};

这应该做你想做的。请注意,您可以进一步抽象并制作另一对结构。

struct false_type {
static const bool value = false;
};

struct true_type {
static const bool value = true;
};

然后 is_same变成:

template<typename, typename>
struct is_same : false_type {};

template<typename T>
struct is_same<T, T> : true_type {};

这使它看起来更像一个函数。

我更喜欢这个而不是类别解决方案,因为它更容易将元程序分离到头文件中。然后您可以在别处重用该逻辑。尽管如此,如果您不使用 c++11 甚至不使用 boost,那么制作必要的编译时函数可能会让人头疼。

如果使用复杂的(或任何简单的重新设计)满足您当前和 future 的需求 - 更喜欢它。否则我认为这个解决方案是合理的 future 证明。

关于C++ Matrix模板,矩阵矩阵和矩阵数字乘法之间的歧义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19393841/

38 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com