표현식 템플릿 트리가 주어지면이를 처리하기 전에 새로운 최적화 된 트리를 만들고 싶습니다. 곱셈 연산의 다음과 같은 예를 생각해표현식 템플릿 트리 변환
(((a * b) * c) * d).
내가 변형 된 표현을 생산하는 싶습니다 때문에 operator*
의 왼쪽에서 오른쪽으로 연관성, 표현 트리에, 생산
a * b * c * d,
곱셈에서 발생하는 트리 오른쪽에서 왼쪽으로 :
(a * (b * (c * d))).
이진 표현 유형을 고려
의해 정의된다template<typename Left, typename Right>
BinaryTimesExpr<Constify<Left>, Constify<Right>> operator*(Left&& l, Right&& r)
{
return {forward<Left>(l), forward<Right>(r)};
}
:
template<typename Left, typename Right>
struct BinaryTimesExpr
{
BinaryTimesExpr() = default;
BinaryTimesExpr(const BinaryTimesExpr&) = default;
BinaryTimesExpr(BinaryTimesExpr&&) = default;
BinaryTimesExpr(Left&& l, Right&& r) : left(forward<Left>(l)), right(forward<Right>(r)) {}
BinaryTimesExpr& operator=(const BinaryTimesExpr&) = default;
BinaryTimesExpr& operator=(BinaryTimesExpr&&) = default;
Left left;
Right right;
};
곱셈 연산자 operator*
정의
template<typename T> struct HelperConstifyRef { using type = T; };
template<typename T> struct HelperConstifyRef<T&> { using type = const T&; };
template<typename T>
using ConstifyRef = typename HelperConstifyRef<T>::type;
및 lvalues로 구성 될 때 CONST 좌변 - 참조와 하위 표현식을 보장하기 위해 사용되며, rvalues로 구성 될 때 rvalues를 복사 (복사/이동)합니다.
template<typename Expr>
auto Transform(const Expr& expr) -> Expr
{
return expr;
}
template<typename Left, typename Right>
auto Transform(const BinaryTimesExpr<Left, Right>& expr) -> type(???)
{
return {(Transform(expr.left), Transform(expr.right))};
}
template<typename Left, typename Right>
auto Transform(const BinaryTimesExpr<BinaryTimesExpr<LeftLeft, LeftRight>, Right>& expr) -> type(???)
{
return Transform({Transform(expr.left.left), {Transform(expr.left.right), Transform(expr.right)}}); // this sintax is invalid...how can I write this?
}
내 질문은 다음과 같습니다 :
이전 상태로 새로운 표현 템플릿 트리를 생성하는 변환 함수를 정의1) 어떻게이 Transform
함수의 반환 형식을 결정합니까? 내가 좋아하는 타입 특성을 사용하여 시도했다 :
template<typename Expr>
struct HelperTransformedExpr
{
using type = Expr;
};
template<typename Left, typename Right>
struct HelperTransformedExpr<BinaryTimesExpr<Left, Right>>
{
using type = BinaryTimesExpr<typename HelperTransformedExpr<Left>::type, typename HelperTransformedExpr<Right>::type>;
};
template<typename LeftLeft, typename LeftRight, typename Right>
struct HelperTransformedExpr<BinaryTimesExpr<BinaryTimesExpr<LeftLeft, LeftRight>, Right>>
{
using type = BinaryTimesExpr<typename HelperTransformedExpr<LeftLeft>::type,
BinaryTimesExpr<typename HelperTransformedExpr<LeftRight>::type, typename HelperTransformedExpr<Right>::type>>;
};
template<typename Expr>
using TransformedExpr = typename HelperTransformedExpr<Expr>::type;
하지만 아래에있는 내 질문 (2)를 해결하기 위해이를 적용하는 방법을 모르겠어요.
return Transform({Transform(expr.left.left), {Transform(expr.left.right), Transform(expr.right)}});
3)이 문제에 대한 청소기 해결책은 있는가 :
2) 어떻게 재귀 라인을 작성하려면 어떻게해야합니까?
편집 :는 DyP는 위의 문제에 대한 부분적인 해결책을 제시한다.
이template<typename Expr>
auto Transform(const Expr& expr) -> Expr
{
return expr;
}
template<typename Left, typename Right>
auto Transform(BinaryTimesExpr<Left, Right> const& expr)
-> decltype(BinaryTimesExpr<decltype(Transform(expr.left)), decltype(Transform(expr.right))>{Transform(expr.left), Transform(expr.right)})
{
return BinaryTimesExpr<decltype(Transform(expr.left)), decltype(Transform(expr.right))>{Transform(expr.left), Transform(expr.right)};
}
template<typename LeftLeft, typename LeftRight, typename Right>
auto Transform(BinaryTimesExpr<BinaryTimesExpr<LeftLeft, LeftRight>, Right> const& expr)
-> decltype(Transform(BinaryTimesExpr<decltype(Transform(expr.left.left)), BinaryTimesExpr<decltype(Transform(expr.left.right)), decltype(Transform(expr.right))>>{Transform(expr.left.left), {Transform(expr.left.right), Transform(expr.right)}}))
{
return Transform(BinaryTimesExpr<decltype(Transform(expr.left.left)), BinaryTimesExpr<decltype(Transform(expr.left.right)), decltype(Transform(expr.right))>>{Transform(expr.left.left), {Transform(expr.left.right), Transform(expr.right)}});
}
int main()
{
BinaryTimesExpr<int, int> beg{1,2};
auto res = beg*3*4*5*beg;
std::cout << res << std::endl;
std::cout << Transform(res) << std::endl;
}
출력 : 대부분의 외장 Transform
통화 이외의 모든 하위 표현에 Transform
기능을 적용 할 필요하다고
(((((1*2)*3)*4)*5)*(1*2))
(1*(2*(3*(4*(5*(1*2))))))
참고 (을 참조 아래에 그의 대답에 내 전체 솔루션을 기반으로 마지막으로 Transform
과부하).
전체 소스 코드는 here입니다.완벽한 전달을 통합하지 않고
이 문제를 해결하기 위해 Boost.Proto를 사용 해본 적이 있습니까? Cpp Next는 지금 당장 다운 된 것으로 보이지만 Proto를 사용하여 수학 표현식을 재정렬하는 방법에 대한 기사를 작성했습니다. 그의 예는 (A + B) [2]가 A [2] + B [2]로되었지만 모두가 단지 연산자이기 때문에 적용해야합니다. – KitsuneYMG
이것은 타사 종속성이 필요하지 않은 라이브러리에 통합 될 예정입니다. – Allan
1) Boost.Proto는 헤더 전용입니다. 2)'((a * b) * c) * d)'를'(a * (b * (c * d)))로 변환하는 메타 프로그래밍 변압기를 원하십니까? 표현 트리를 직접'(a * (b * (c * d)))'? – dyp