1

Boost.Proto に慣れるために、ユーザー ガイドの TArray の例を適用して、固定されているが任意のサイズの浮動小数点ベクトル用のさらに別の式テンプレート ライブラリを構築しようとしています。最初に行うことは、ベクター クラスを定義することです。

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[]それ自体をオーバーロードして、端末に対して返されるvector_context派生元で評価します。proto::callable_contextvector[index]FPVector

コードをコンパイルして非常に単純なステートメント ( ) で呼び出すと、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 ++は可能な候補のものをリストします...それから私が理解しているのは、定義するvector_expr_wrapper前にの定義全体を提供する必要があるということですが、他のすべてが(文法、評価コンテキスト...)に依存するFPVectorため、そうすることができません。vector_expr_wrapperFPVector

これを解決するにはどうすればよいですか (つまり、クラスをどのようにレイアウトすればよいですか)?

TArray の例は、配列クラスを非常に遅く定義し、その型をint[3]before で指定することによって、この問題を回避しています。これは、私のコンテキストでは再現できないと思います。

ご助力ありがとうございます!

4

1 に答える 1

2

これが私の解決策です:

#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 >

vector_expr_wrapper(具体的な) クラス ( )の不完全なクラス テンプレート ( ) から継承することはできませんFPVector。また、FPVectorタイプはそれ自体のコピーを含めようとしています。proto::terminalオブジェクト型のラッパーです。それは物自体の代役と考えてください。その場合、それから継承したり、それから継承したものから継承したりすることはできません。

私が投稿したコードの唯一の真のトリックは、proto::is_proto_expr. boost::protoこれは、名前空間で定義された演算子のオーバーロードを検出するために ADL を起動させる厄介なハックです。このことは、プロトのドキュメントの「The extends<> Expression Wrapper」セクションの下部にある警告に詳しく説明されています。

于 2013-08-21T19:00:26.280 に答える