У меня есть объект данных, с которым я пытаюсь заставить всех операторов работать. Это один кусок данных с переменными ptrs в нем, и имеет любое количество разных типов и размеров и еще много чего. Типы обрабатываются с помощью перечислений и шаблонов и операторов switch. Таким образом, для каждого x, d [x] является одним типом, с любым числом из них, и они могут быть векторами. так что д [х] [у] и д [х] [у] [г]. Я сделал внутренний вспомогательный объект, чтобы помочь с этим. Так что я [] перегружен, чтобы делать подобные вещи, и он вернет правильный тип штрафа: (gcc 4.6.1)
[Редактировать: у меня та же проблема с d (x, y, z) — проблема не в операторе []]int i = d[0][3][5];
Я перегружаю T () в этом вспомогательном объекте.
template <class T>
data::helper::operator T (); // switch(x)...return different types
data::helper data::operator [] (int i); // recurse, return helper(t, d, x, i, j);
Так что я просто верну этот объект, который разрешает его тип в этот момент (переключитесь с делами, связанными с t-> get< char> (d, x, i, j) и т. д.). Так что проблема в том, если я хочу сделать что-то подобное
int i = d[0][1] + d[4][2];
if (d[5][1] != d[3][0]) ...
затем мне пришлось перегрузить каждый оператор, чтобы получить этот вспомогательный объект временного массива. И теперь я сталкиваюсь с необходимостью сделать временное значение там иногда для некоторых операторов, что является болью.
По сути, мне кажется, что сначала мне нужно разрешить оператор T (), прежде чем компилятор попытается взять два из них и добавить их.
В любом случае я должен сделать это для операторов = и + = и т. Д., Но я хотел бы удалить эти макросы jazillion, помогая мне определить все эти другие операторы.
Кроме того, я чувствую, что если бы я мог как-то перегрузить оператор lvalue, я не мог бы беспокоиться об операторе =. Может быть, это и &() (который сейчас просто возвращает шаблонный ptr). …? Или, на самом деле, это больше, чем я имею в виду, по крайней мере, для d [] = что-то, но у меня это не работает. Я не уверен, как преобразовать ptr любого типа в это возвращаемое значение.
data::helper & data::operator [] (int i);
У меня большая часть этого работает, но это много кода, и я думаю, что мне придется добавить дополнительный оператор if для каждого доступа, чтобы делать временные вещи, что я не хочу делать. Так что я пропустил?
Редактировать: использование d (x, i, j) аналогично d [x] [i] [j]. Я почти уверен, что делаю хотя бы начальную часть того, что используется в ссылке n.m. вывешенный. Проблема заключается в том, что последний вспомогательный объект разрешается в свои данные, прежде чем он будет использован в выражении. Каким-то образом компилятору нужен оператор, который принимает вспомогательный объект, даже если он знает, как разрешить его, когда он один … Я думаю. Я потратил пару дней на перегрузку каждого оператора, поэтому я забыл все детали. 🙂
Но главная проблема сейчас с такими вещами:
helper operator + (helper & l, helper & r)
Я хотел бы определить следующее, но оно не используется — тогда я думаю, что мои проблемы могут быть решены. похожая история для унарных операций ~, — и postfix ++, -.
template <class T> T operator + (helper & l, helper & r)
Но все это только потому, что что-то не так с моим T (), я думаю. Большая часть этого является новой для меня, поэтому я держу пари, что что-то упустил
Практический способ сделать это — использовать шаблоны выражений.
Я бы изменил ваши возвращаемые значения с operator[]
даже к шаблону выражения.
Это будет использовать функции C ++ 11, потому что это делает его короче.
enum class ExpressionType { Index, Addition };
template< ExpressionType Op, typename LHS, typename RHS >
struct Expression {
LHS lhs;
RHS rhs;
template<typename T>
operator T();
};
// to separate out the evaluation code:
template< typename T, ExpressionType Op, typename LHS, typename RHS >
struct Evaluate {
T operator()( Expression<Op, LHS, RHS> exp ) const;
};
template< ExpressionType Op, typename LHS, typename RHS >
template<typename T>
Expression<Op,LHS,RHS>::operator T() {
return Evaluate<T,Op,LHS,RHS>()( std::move(*this) );
}
// further specializations needed:
template< typename T, typename RHS >
struct Evaluate< T, ExpressionType::Index, data, RHS > {
T operator()( Expression<Op, ExpressionType::Index, data, RHS> exp ) const {
// we just assume RHS can be treated like an integer. If it cannot,
// we fail to compile. We can improve this with SFINAE elsewhere...
return exp.lhs.get_nth(exp.rhs);
}
};
template< typename T, typename LHS, typename RHS >
struct Evaluate< T, ExpressionType::Addition, LHS, RHS > {
T operator()( Expression<Op, ExpressionType::Index, data, RHS> exp ) const {
// code with all of LHS, RHS and T visible!
}
};
template<typename E>
struct is_expression : std::false_type {};
template<ExpressionType Op, typename LHS, typename RHS>
struct is_expression<Expression<Op,LHS,RHS> : std::true_type {};
template<ExpressionType Op, typename LHS, typename RHS>
Expression<Op, LHS, RHS> make_expression( LHS&& lhs, RHS&& rhs ) {
return { std::forward<LHS>(lhs), std::forward<RHS>(rhs) };
}
// here is why I want to start out with returning an expression. This SFINAE test
// is extremely easy because of that -- we overload operator+ on any two types, so long
// as one of them is an Expression!
template<typename LHS, typename RHS, typename=typename std::enable_if<is_expression<LHS>::value || is_expression<RHS>::value >::type>
ExpressionType<ExpressionType::Addition, LHS, RHS> operator+( LHS&& lhs, RHS&& rhs )
{
return make_expression<ExpressionType::Addition>(std::forward<LHS>(lhs), std::forward<RHS>(rhs) );
}
идея заключается в том, что мы строим во время компиляции дерево шаблонов, которые представляют порядок, в котором различные выражения оцениваются компилятором.
Когда мы, наконец, приведем его к конкретному типу T
Только тогда мы начнем работу по оценке.
Это избавляет от необходимости создавать временные файлы, но означает, что нам нужно сделать много шаблонов mojo, чтобы все заработало. Выше приведен эскиз такого генератора дерева шаблонных выражений.
Чтобы увидеть полную реализацию простого случая, вот ссылка на википедиястатья на эту тему, где создана полноценная система деревьев выражений, чтобы сделать std::vector
векторная обработка без временных.
Других решений пока нет …