У меня в настоящее время есть иерархия классов, подобная
MatrixBase -> DenseMatrix
-> (other types of matrices)
-> MatrixView -> TransposeView
-> DiagonalView
-> (other specialized views of matrices)
MatrixBase
- абстрактный класс, который вынуждает разработчиков определять operator () (int, int) и тому подобное; он представляет 2-х мерные массивы чисел. MatrixView
представляет (возможно изменяемый) способ просмотра матрицы, например, ее транспонирование или подматрицу. Смысл MatrixView
в том, чтобы иметь возможность сказать что-то вроде
Scale(Diagonal(A), 2.0)
где Diagonal
возвращает объект DiagonalView
, который является своего рода облегченным адаптером.
Теперь вот вопрос (ы). Я буду использовать очень простую матричную операцию в качестве примера. Я хочу определить функцию как
template <class T>
void Scale(MatrixBase<T> &A, const T &scale_factor);
, который делает очевидную вещь, которую предлагает название. Я хочу быть в состоянии передать либо матрицу отсутствия представления о честности, либо экземпляр подкласса MatrixView
. Прототип, как написано выше, не работает для таких утверждений, как
Scale(Diagonal(A), 2.0);
, поскольку объект DiagonalView
, возвращаемый Diagonal
, является временным, а Scale
принимает неконстантную ссылку, которая не может принять временную. Есть ли способ сделать эту работу? Я пытался использовать SFINAE, но я не очень хорошо понимаю это, и я не уверен, что это решит проблему. Для меня важно, чтобы эти шаблонные функции можно было вызывать без предоставления явного списка аргументов шаблона (я хочу неявную реализацию). В идеале вышеприведенное утверждение может работать как написано.
Редактировать: (следующий вопрос)
Как sbi ответил ниже о ссылочных и временных значениях rvalue, есть ли способ определить две версии Scale, одну, которая принимает неконстантную ссылку на rvalue для не-представлений, и другую, которая принимает представление по значению? Проблема состоит в том, чтобы различать эти два во время компиляции таким образом, чтобы неявная реализация работала.
Обновление
Я изменил иерархию классов на
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);
}
Обратите внимание, что существует две версии: одна для константного представления и неконстантная версия для реальных матриц. Это означает, что для таких функций, как Mult(A, B, C)
, мне потребуется 8 перегрузок, но по крайней мере это работает. Однако, что не работает, так это использование этих функций в других функциях. Видите ли, каждый View
-подобный класс содержит член View
того, на что он смотрит; например, в выражении Diagonal(SubMatrix(A))
функция Diagonal
возвращает объект типа DiagonalView<SubMatrixView<T> >
, который должен знать полностью производный тип A
. Теперь предположим, что в Scale
я вызываю какую-то другую функцию, подобную этой, которая принимает либо базовое представление, либо ссылку на матрицу. Это потерпит неудачу, потому что для построения необходимых View
требуется производный тип аргумента Scale; информации у него нет. Все еще работаем над поиском решения этой проблемы.
Обновление
Я использовал собственную версию Boost's enable_if для выбора между двумя различными версиями функции, например Scale
. Это сводится к маркировке всех моих классов матриц и представлений с помощью дополнительных тегов typedef, указывающих, доступны ли они для чтения и записи, а также для просмотра или отсутствия просмотра. В конце мне все еще нужно 2 ^ N перегрузок, но теперь N - это только число неконстантных аргументов. Для окончательного результата см. здесь (вряд ли он будет серьезно обновлен снова).