今天我面临一个伤害我安心的问题。我已经在一个非常聪明且有意义的例子中恢复了我的问题,虽然没有产生错误但是没有达到预期的结果。
#include <iostream>
namespace MATH {
template <std::size_t M, std::size_t N, class T>
class Matrix
{
};
void invert(Matrix<2, 2, double>& m)
{
std::cout << "DIM 2 : MATH version (use of the determinant)" << std::endl;
}
void invert(Matrix<3, 3, double>& m)
{
std::cout << "DIM 3 : MATH version (use of the determinant)" << std::endl;
}
}
namespace GEOM {
template <std::size_t N>
using Matrix = MATH::Matrix<N, N, double>;// orthonormal set of vectors
template <std::size_t N>
void invert(Matrix<N>& m)
{
std::cout << "DIM " << N << " : GEOM version (use of the transpose)" << std::endl;
}
void geom_foo_purpose(Matrix<3>& m)
{
invert(m);
}
}
int main(int argc, char **argv)
{
GEOM::Matrix<3> m;
GEOM::geom_foo_purpose(m);
return 0;
}
output : std::cout << "DIM 3 : MATH version (use of the determinant)" << std::endl;
在geom_foo_purpose定义中,对反转的调用导致不合格的id,因为请求了模板推导。所以,ADL能够说:好的,让我们看一下MATH命名空间。允许MATH :: invert优先于GEOM :: invert版本的事实,因为我认为非模板版本具有优先权是不可接受的。
例如,我想首先通过将Matrix类定义为GEOM类型来开发GEOM内容。调用GEOM :: invert。没问题。 有一天,我想在另一个命名空间MATH中推广我的Matrix类,我想:好吧,我保持相同的方法,我不打破代码。只需使用MATH :: Matrix ......我就无法理解性能开销在哪里以及为什么某些敏感措施会发生变化。
所以我实际上考虑了三个解决方案:
有没有一个可行的方法来克服这个问题?
答案 0 :(得分:1)
问题是,您的GEOM::Matrix
只是MATH::Matrix
的同义词,而不是GEOM
中的新类型。这是using
语句的预期效果,因此参数依赖名称查找将MATH::invert()
视为最佳匹配。
如果你想解决这个问题,请用这种方式定义一个真实的GEOM::Matrix
:
template <std::size_t N>
class Matrix : public MATH::Matrix<N, N, double> {};// orthonormal set of vectors
修改强>
您必须决定一个基本的设计问题:
答案 1 :(得分:0)
最佳做法是将设计为在一个命名空间中协同工作的类和函数保持为启用ADL。 (参见C ++编码标准中的第57项:将类型及其非成员函数接口保存在同一名称空间。)有时建议将不相关的类和函数保存在不同的名称空间中。 (参见同一本书中的第58项。)我发现这个限制太多,因为它很快就会创建一个巨大的命名空间丛林。
更常见的做法是将逻辑上属于一个库的所有内容放入一个名称空间中。图书馆有责任避免内部名称冲突。库的用户通常不应该向库名称空间添加新内容。这几乎是标准库,boost,OpenCV和许多其他库的工作方式。这就是我的建议。不要试图过分。它只是伤害你的头,没有必要。
这些公共库出于某些目的使用嵌套命名空间,例如boost::detail
用于实现细节,这对于库的用户来说应该不是很有用。需要更多名称空间的其他示例是
修改强>
如果我理解正确,您的GEOM::Matrix
应该是正交矩阵。 (我只是注意到这一点,并且会建议一个更明确的名称。)这应该是一个不同的类型,这种类型必须ensure the internal invariant是正交的。使用using
或typedef
只会出现别名,并且您无法保证,如果通过某些MATH::Matrix
函数中断,则不会出现不变量。因此,我建议将构图作为解决问题的手段:
namespace GEOM
{
template <std::size_t N, typename T>
class OrthogonalMatrix
{
private:
MATH::Matrix<N,N,T> mat;
public:
// Enable use of const interface of MATH::Matrix<N,N,T>.
operator const MATH::Matrix<N,N,T> &() const { return mat; }
// ... here goes the implementation ensuring
// orthogonality at all times.
};
} // end of namespace GEOM
另一种选择是私有继承,它允许您使用关键字MATH::Matrix
选择性地公开using
方法,如下所示:
namespace GEOM
{
template <std::size_t N, typename T>
class OrthogonalMatrix : private MATH::Matrix<N,N,T>;
{
public:
// Make `MATH::Matrix<N,N,T>::transposeInPlace` publicly accessible
using MATH::Matrix<N,N,T>::transposeInPlace;
// Enable use of const interface of MATH::Matrix<N,N,T>.
operator const MATH::Matrix<N,N,T> &() const { return *this; }
// ... here goes the implementation ensuring
// orthogonality at all times.
};
} // end of namespace GEOM
您不应该使用构造函数或条目访问函数来执行此操作,因为它们将使类的用户能够破坏不变量,这很容易导致很多混淆。私有部分中的公共继承加using
也是错误的,因为类的用户仍然可以通过转换为MATH::Matrix<N,N,T> &
来破坏不变量,然后搞乱矩阵。