Мы пишем библиотеку шаблонов выражений для обработки операций со значениями с вектором разреженного градиента (автоматическое дифференцирование первого порядка).Я пытаюсь выяснить, как сделать возможным вложение вложенных выражений по ссылке или по значениям в зависимости от того, являются ли выражения временными или нет.
У нас есть класс Scalar, который содержит значение и разреженный градиентвектор.Мы используем шаблоны выражений (например, Eigen), чтобы предотвратить создание и выделение слишком многих временных объектов Scalar
.Таким образом, у нас есть класс Scalar
, унаследованный от ScalarBase<Scalar>
(CRTP).
Бинарная операция (например, +, *) между объектами типа ScalarBase< Left >
и ScalarBase< Right >
возвращает объект ScalarBinaryOp<Left, Right,BinaryOp>
, которыйнаследуется от ScalarBase< ScalarBinaryOp<Left, Right,BinaryOp> >
:
template< typename Left, typename Right >
ScalarBinaryOp< Left, Right, BinaryAdditionOp > operator+(
const ScalarBase< Left >& left, const ScalarBase< Right >& right )
{
return ScalarBinaryOp< Left, Right, BinaryAdditionOp >( static_cast< const Left& >( left ),
static_cast< const Right& >( right ), BinaryAdditionOp{} );
}
ScalarBinaryOp
должен содержать значение или ссылку на операндные объекты типа Left
и Right
.Тип держателя определяется специализацией шаблона RefTypeSelector< Expression >::Type
.
В настоящее время это всегда постоянная ссылка.В настоящее время это работает для наших тестовых случаев, но кажется неправильным или небезопасным хранить ссылку на временные подвыражения.
Очевидно, мы также не хотим, чтобы объект Scalar
, содержащий вектор разреженного градиента, был скопирован,Если x
и y
равны Scalar
, выражение x+y
должно содержать постоянную ссылку на x
и y
.Однако, если f
является функцией от Scalar
до Scalar
, x+f(y)
должна содержать константную ссылку на x
и значение f(y)
.
Следовательно, я хотел бы передатьинформация о том, являются ли подвыражения временными или нет.Я могу добавить это к параметрам типа выражения:
ScalarBinaryOp< typename Left, typename Right, typename BinaryOp , bool LeftIsTemporary, bool RightIsTemporary >
и к RefTypeSelector
:
RefTypeSelector< Expression, ExpressionIsTemporary >::Type
Но тогда яДля каждого бинарного оператора необходимо определить 4 метода:
ScalarBinaryOp< Left, Right, BinaryAdditionOp, false, false > operator+(
const ScalarBase< Left >& left, const ScalarBase< Right >& right );
ScalarBinaryOp< Left, Right, BinaryAdditionOp, false, true > operator+(
const ScalarBase< Left >& left, ScalarBase< Right >&& right );
ScalarBinaryOp< Left, Right, BinaryAdditionOp, true, false > operator+(
ScalarBase< Left >&& left, const ScalarBase< Right >& right );
ScalarBinaryOp< Left, Right, BinaryAdditionOp, true, true > operator+(
ScalarBase< Left >&& left, ScalarBase< Right >&& right )
Я бы предпочел добиться этого при совершенной пересылке.Однако я не знаю, как я могу достичь этого здесь.Во-первых, я не могу использовать простые «универсальные ссылки», потому что они совпадают почти с чем угодно.Я предполагаю, что возможно было бы объединить универсальные ссылки и SFINAE, чтобы разрешить только определенные типы параметров, но я не уверен, что это правильный путь.Также я хотел бы знать, могу ли я закодировать информацию о том, были ли Left и Right изначально ссылками lvalue или rvalue в типах Left и Right, которые параметризуют ScalarBinaryOp
вместо использования 2 дополнительных логических параметров, и как получить эту информацию.
Я должен поддерживать gcc 4.8.5, который в основном совместим с c ++ 11.