gpt4 book ai didi

c++ - Boost.原型(prototype) : General class layout for an EDSL with custom terminal classes

转载 作者:行者123 更新时间:2023-11-30 04:15:34 24 4
gpt4 key购买 nike

为了熟悉 Boost.Proto,我正在尝试通过改编用户指南中的 TArray 示例,为固定但任意大小的浮点 vector 构建另一个表达式模板库。我做的第一件事是定义我的 vector 类:

typedef double real;

// Forward-declare an expression wrapper
template<typename Expr>
struct vector_expr_wrapper; // line 13

class FPVector : vector_expr_wrapper< proto::terminal< FPVector >::type > { // line 16
public:
FPVector() : numElements(0), elements(0) {}
FPVector(size_t n) : numElements(n), elements(new real[n]) {}
~FPVector() { delete[] elements; }

real& operator[](size_t i) { return elements[i]; }

template<typename Expr>
FPVector const& operator=(vector_expr_wrapper<Expr> vec_expr) {
for(size_t i=0; i<numElements; i++) {
elements[i] = vec_expr[i];
}
return *this;
}

private:
size_t numElements;
real * elements;
};

vector_expr_wrapper 还重载了它的 operator[] 以使用派生自 proto::callable_contextvector_context 评估自身为 FPVector 终端返回 vector[index]

当我编译代码并使用非常简单的语句 (a = b + c;) 调用它时,我收到错误消息:

../main.cpp:16:18: error: invalid use of incomplete type ‘struct vector_expr_wrapper<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<FPVector>, 0l> >’
../main.cpp:13:8: error: declaration of ‘struct vector_expr_wrapper<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<FPVector>, 0l> >’
../main.cpp: In function ‘int main()’:
../main.cpp:121:8: error: no match for ‘operator+’ in ‘b + c’

然后 g++ 列出了可能的候选内容...我从中了解到,我必须在定义 FPVector 之前给出 vector_expr_wrapper 的完整定义,但我不能这样做,因为 vector_expr_wrapper 中的所有其他内容取决于 FPVector(语法、评估上下文...)

我该如何解决这个问题(即我应该如何布局我的类(class))?

TArray 示例规避了这个问题——我猜——通过在很晚的时候定义它们的数组类并在之前用 int[3] 指定它的类型,我认为我无法在我的上下文中重现.

非常感谢您的帮助!

最佳答案

这是我的解决方案:

#include <vector>
#include <iostream>
#include <boost/proto/proto.hpp>
#include <boost/format.hpp>

namespace proto = boost::proto;
using proto::_;

typedef double real;

struct vector_grammar
: proto::or_<
proto::terminal< std::vector<real> >
, proto::plus< vector_grammar, vector_grammar >
, proto::minus< vector_grammar, vector_grammar >
, proto::multiplies< vector_grammar, vector_grammar >
, proto::divides< vector_grammar, vector_grammar >
>
{};

template<typename Expr>
struct vector_expr;

// Tell proto that in the vector_domain, all
// expressions should be wrapped in vector_expr<> and
// must conform to the vector_grammar
struct vector_domain
: proto::domain<
// use_basic_expr here instructs proto to use the stripped-
// down proto::basic_expr instead of proto::expr to reduce
// compile times. It's not necessary.
proto::use_basic_expr<proto::pod_generator<vector_expr> >
, vector_grammar
>
{};

struct vector_subscript_context
: proto::callable_context< vector_subscript_context const >
{
typedef real result_type;

explicit vector_subscript_context(std::ptrdiff_t i)
: i_(i)
{}

// Index array terminals with our subscript. Everything
// else will be handled by the default evaluation context.
real operator ()(proto::tag::terminal, std::vector<real> const &data) const
{
return data[this->i_];
}

private:
std::ptrdiff_t i_;
};

// Forward-declare an expression wrapper
template<typename Expr>
struct vector_expr
{
BOOST_PROTO_BASIC_EXTENDS(Expr, vector_expr<Expr>, vector_domain)

// Use the vector_subscript_context to implement subscripting
// of a vector_expr expression tree.
real operator []( std::ptrdiff_t i ) const
{
vector_subscript_context const ctx(i);
return proto::eval(*this, ctx);
}
};

template<typename = proto::is_proto_expr>
struct FPVector_
: vector_expr<
proto::basic_expr<
proto::tag::terminal
, proto::term< std::vector<real> >
>
>
{
explicit FPVector_(std::size_t n = 0)
{
proto::value(*this).resize(n);
}

real & operator[](std::ptrdiff_t i)
{
return proto::value(*this)[i];
}

real const & operator[](std::ptrdiff_t i) const
{
return proto::value(*this)[i];
}

template<typename Expr>
FPVector_ & operator=(vector_expr<Expr> const & that)
{
std::ptrdiff_t const size =
static_cast<std::ptrdiff_t>(proto::value(*this).size());
for(std::ptrdiff_t i = 0; i < size; ++i)
proto::value(*this)[i] = that[i];
return *this;
}
};

typedef FPVector_<> FPVector;

int main()
{
FPVector a(3), b(3), c(3);
for(std::ptrdiff_t i = 0; i < 3; ++i)
b[i] = c[i] = i;

a = b + c;

std::cout
<< boost::format("a = {%d, %d, %d}") % a[0] %a[1] %a[2]
<< std::endl;
}

您显示的代码有很多问题:

// Forward-declare an expression wrapper
template<typename Expr>
struct vector_expr_wrapper; // line 13

class FPVector : vector_expr_wrapper< proto::terminal< FPVector >::type >

您不能从(具体)类(FPVector)继承不完整的类模板(vector_expr_wrapper)。此外,您的 FPVector 类型正试图包含其自身的拷贝。 proto::terminal 是对象类型的包装器。将其视为事物本身的替代品,但带有一些额外的 Proto 香料。然后从它继承或从它继承的东西是不会飞的。

我发布的代码中唯一真正的技巧是使用 proto::is_proto_expr。这是一个让 ADL 启动查找 boost::proto 命名空间中定义的运算符重载的讨厌的 hack。 "The extends<> Expression Wrapper" section底部的警告中详细描述了这件事proto 的文档。

关于c++ - Boost.原型(prototype) : General class layout for an EDSL with custom terminal classes,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18232109/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com