C++ C++;隐式模板实例化

C++ C++;隐式模板实例化,c++,templates,metaprogramming,C++,Templates,Metaprogramming,我目前有一个类层次结构,如 MatrixBase -> DenseMatrix -> (other types of matrices) -> MatrixView -> TransposeView -> DiagonalView -> (other specialized views of matrices) Ma

我目前有一个类层次结构,如

MatrixBase -> DenseMatrix
           -> (other types of matrices)
           -> MatrixView -> TransposeView
                         -> DiagonalView
                         -> (other specialized views of matrices)
MatrixBase
是一个抽象类,它强制实现者定义operator()(int,int)等;它表示二维数字数组
MatrixView
表示一种(可能是可变的)查看矩阵的方式,例如对矩阵进行转置或获取子矩阵。MatrixView的要点是能够说

Scale(Diagonal(A), 2.0)
其中
Diagonal
返回一个
DiagonalView
对象,它是一种轻量级适配器

现在问题来了。我将使用一个非常简单的矩阵运算作为示例。我想定义一个函数,比如

template <class T>
void Scale(MatrixBase<T> &A, const T &scale_factor);
因为
Diagonal
返回的
DiagonalView
对象是临时对象,并且
Scale
采用非常量引用,该引用不能接受临时对象。有什么办法可以让这一切顺利进行吗?我试着使用SFINAE,但我不太了解它,我不确定这是否能解决问题。对我来说,在不提供显式模板参数列表的情况下调用这些模板化函数是很重要的(我想要隐式实例化)。理想情况下,上述声明可以按书面形式进行


编辑:(后续问题)

正如sbi在下面回答的关于右值引用和临时值的问题一样,是否有办法定义两种版本的量表,一种是对非视图采用非常量右值引用,另一种是采用传递值视图?问题是在编译时以隐式实例化可以工作的方式区分这两者


更新

我已将类层次结构更改为

ReadableMatrix
WritableMatrix : public ReadableMatrix
WritableMatrixView
DenseMatrix : public WritableMatrix
DiagonalView : public WritableMatrixView
WritableMatrixView
WritableMatrix
不同的原因是视图必须通过常量引用传递,而矩阵本身必须通过非常量引用传递,因此访问器成员函数具有不同的常量。现在像Scale这样的函数可以定义为

template <class T>
void Scale(const WritableMatrixView<T> &A, const T &scale_factor);
template <class T>
void Scale(WritableMatrix<T> &A, const T &scale_factor){
    Scale(WritableMatrixViewAdapter<T>(A), scale_factor);
}
模板
无效比例(常量可写矩阵查看和分析、常量T和比例系数);
模板
空标度(可写矩阵和A、常数和标度因数){
标度(可写矩阵十六适配器(A)、标度因数);
}
请注意,有两个版本,一个用于常量视图,另一个用于实际矩阵的非常量版本。这意味着对于像
Mult(A,B,C)
这样的函数,我需要8个重载,但至少它可以工作。但是,不起作用的是在其他函数中使用这些函数。你看,每个类似
视图的类都包含一个成员
视图
;例如,在表达式
Diagonal(子矩阵(A))
中,
Diagonal
函数返回类型为
DiagonalView
的对象,该对象需要知道
A
的完全派生类型。现在,假设在
Scale
中,我调用了其他类似的函数,它采用基本视图或矩阵引用。这将失败,因为所需的
视图的构造需要Scale参数的派生类型;它所没有的信息。仍在努力寻找解决方案


更新


我使用了Boost的enable_的一个自制版本,可以在两个不同版本的函数之间进行选择,比如
Scale
。它归结为使用额外的typedef标记标记所有我的矩阵和视图类,指示它们是可读写的,是视图还是非视图。最后,我仍然需要2^N重载,但现在N只是非常量参数的数量。有关最终结果,请参阅(不太可能再次进行认真的修改)。

解决此问题的简单方法是使用
boost::shared\u ptr
而不是引用。

可能是,您应该使用
const

template <class T>
void Scale(const MatrixBase<T> &A, const T &scale_factor);
模板
空隙率(常数矩阵基和A、常数T和比例系数);

您正在限制Scale的第一个参数的类型,但您可以让编译器自己确定适合的类型,如下所示:

template <class M,class T>
void Scale(M A, const T &scale_factor);
模板
空隙率(MA、常数和比例系数);

不要使用引用,按值传递


如果需要,让copy elision为您进行优化。

这与模板无关。你的榜样

Scale(Diagonal(A), 2.0);
可以推广到

f(g(v),c);
在C++03中,这要求每个副本或每个
const
引用传递
f()
的第一个参数。原因是
g()
返回一个临时的右值。但是,右值仅绑定到常量引用,而不绑定到非常量引用。这与是否涉及模板、SFINAE、TMP等无关。这就是语言(目前)的方式

这背后还有一个理由:如果
g()
返回一个临时值,并且
f()
修改了该临时值,那么没有人有机会“看到”修改后的临时值。因此,修改是徒劳的,整个事情很可能是一个错误

据我所知,在你的例子中,
g()
的结果是一个临时的,它是对其他对象(
v
)的视图,因此修改它会修改
v
。但如果是这样的话,在当前C++中,<代码>()>代码>的结果必须是“代码> const < /COD>”(这样它就可以绑定到<代码> const <代码> >,或者必须复制它。 然而,还有更多。C++1x将引入所谓的右值引用。我们所知的“引用”将被分为左值引用或右值引用。您将能够让函数接受右值引用,甚至基于“l/右值”重载这被认为是为了允许类设计者重载右值右边的复制构造函数和赋值,并让它们“偷”t
f(g(v),c);
template <class T>
void Scale(MatrixBase<T> &matrix, const T &scale_factor);

template <class T>
void Scale(DiagonalView<T> view, const T &scale_factor);
template<bool B>
struct boolean { enum { result = B }; };

template< typename T >
class some_matrix {
  public:
    typedef boolean<false> is_view;
  // ...
};

template< typename T >
class some_view {
  public:
    typedef boolean<true> is_view;
  // ...
};

namespace detail {
  template< template<typename> class Matrix, typename T >
  void Scale(Matrix<T>& matrix, const T& scale_factor, boolean<true>)
  {
    /* scaling a matrix*/
  }
  template< template<typename> class Matrix, typename T >
  void Scale(View<T>& matrix, const T& scale_factor, boolean<true>)
  {
    /* scaling a view */
  }
}

template< template<typename> class Matrix, typename T >
inline void Scale(Matrix<T>& matrix, const T& scale_factor)
{
  detail::Scale( matrix, scale_factor, typename Matrix<T>::is_view() );
}