2013-03-27 1 views
5

Boost Phoenix式をC++の代表的な文字列に変換できますか?私が持っている可能性があり:私は、この例では、いくつかの大まかなエッジを持って感謝しますが、これらの線に沿って何かが試みられている場合、私は疑問に思うブーストフェニックスの表現を文字列化できますか?

template <class T1, class T2> 
struct foo { 
    auto operator()(T1 x1, T2 x2) 
    -> decltype(x1 < x2) 
    { return x1 < x2; } 
}; 

stringify(_1<_2); 

、その後のようなものを含む文字列を生成可能性がありますか?

+1

なぜこれをやりたいですか? –

+0

トリッキー。 'stringify(_1 <2);'は_almost_と同じですが、全く異なる展開をしています。 (単項関数) – MSalters

+1

質問が分かりません。 '_1 <_2'は2つの引数をとり、' bool'を返す関数を定義します。 'foo'は2つの引数をとり、' x'または 'y'を返す関数を定義しています。両者の関係は何ですか? –

答えて

3

変換evalを使用すると、hereが「インスピレーション」であることがわかります。

Live example

#include <iostream> 
#include <string> 
#include <sstream> 

#include <boost/phoenix.hpp> 
#include <boost/phoenix/core/arity.hpp> 
#include <boost/lexical_cast.hpp> 

namespace phx=boost::phoenix; 
namespace proto=boost::proto; 

struct do_print : proto::callable 
{ 
    typedef std::string result_type; 

    template <typename NotArgument> 
    std::string operator()(NotArgument n) 
    { 
     return boost::lexical_cast<std::string>(n); 
    } 

    template <int I> 
    std::string operator()(phx::argument<I>) 
    { 
     return std::string("x")+boost::lexical_cast<std::string>(I-1); 
    } 

#define UNARY_OP(TAG, OP)              \ 
    template<typename Arg>              \ 
    std::string operator()(proto::tag::TAG, Arg arg) const       \ 
    {                   \ 
     return std::string("(") + OP + arg + ")";               \ 
    }                   \ 
    /**/ 

#define BINARY_OP(TAG, OP)              \ 
    template<typename Left, typename Right>          \ 
    std::string operator()(proto::tag::TAG, Left left, Right right) const   \ 
    {                   \ 
     return std::string("(") + left + OP + right + ")";             \ 
    }                   \ 
    /**/ 

    UNARY_OP(negate, "-") 
    BINARY_OP(plus, "+") 
    BINARY_OP(minus, "-") 
    BINARY_OP(multiplies, "*") 
    BINARY_OP(divides, "/") 
    BINARY_OP(less, "<") 
    BINARY_OP(greater, ">") 
    /*... others ...*/ 
}; 

struct print_expression 
    : proto::or_< 
     proto::when<proto::terminal<proto::_>, do_print(proto::_value)> 
     , proto::otherwise<do_print(proto::tag_of<proto::_>(), print_expression(proto::pack(proto::_))...)> 
    > 
{}; 

struct do_get_arity : proto::callable 
{ 
    typedef int result_type; 

    template <typename NotArgument> 
    int operator()(NotArgument) 
    { 
     return 0; 
    } 

    template <int I> 
    int operator()(phx::argument<I>) 
    { 
     return I; 
    } 


    template<typename Tag, typename Arg>              
    int operator()(Tag, Arg arg) const       
    {                   
     return arg;               
    }                   
    /**/ 

    template<typename Tag, typename Left, typename Right>          
    int operator()(Tag, Left left, Right right) const   
    {                   
     return std::max(left,right);             \ 
    }                   

}; 

struct get_arity 
    : proto::or_< 
     proto::when<proto::terminal<proto::_>, do_get_arity(proto::_value)> 
     , proto::otherwise<do_get_arity(proto::tag_of<proto::_>(),get_arity(proto::pack(proto::_))...)> 
    > 
{}; 




template <typename Expr> 
std::string stringify(const Expr& expr, const std::string& name="foo") 
{ 
    std::stringstream result; 
    int current_arg; 
    int arity= get_arity()(expr); 

    result << "template <"; 

    for(current_arg=0;current_arg<arity-1; ++current_arg) 
     result << " typename T" << current_arg << ","; 
    result << " typename T" << current_arg; 

    result << " >\n"; 
    result << "struct " << name << " {\n\t"; 
    result << "auto operator()("; 

    for(current_arg=0;current_arg<arity-1; ++current_arg) 
     result << " T" << current_arg << " x" << current_arg << ","; 
    result << " T" << current_arg << " x" << current_arg; 
    result << ")\n\t\t-> typename std::remove_reference< decltype(" << print_expression()(expr) << ") >::type\n"; 
    result << "\t{ return " << print_expression()(expr) << "; }\n"; 
    result << "};\n"; 

    return result.str(); 
} 

int main() 
{ 
    using phx::placeholders::_1; 
    using phx::placeholders::_2; 
    using phx::placeholders::_3; 
    std::cout << stringify(-_1) << std::endl; 
    std::cout << stringify(_1+_2) << std::endl; 
    std::cout << stringify(_1+_2*_3) << std::endl; 

    std::cout << stringify((_1+_2)*_3) << std::endl; 
    std::cout << stringify(_1>2) << std::endl; 
    std::cout << stringify(_1*(-_2)) << std::endl; 
    return 0; 
} 
+0

興味深いように、私は後でそれを実行します。 – user2023370

+0

非常にうまくいった。 – user2023370

-2

文字列化はプリプロセッサ機能です。プリプロセッサで使用できるトークンのみを文字列化できます。型の処理(型と式の展開を含む)はの後に実行されるコンパイラによって行われます。のプリプロセッサのため、必要な文字列化を実行する方法がありません。

+1

文字通り「ストリンジェライズ」していると思います。これはプリプロセッサで行うべきではないという前提がありません。結局のところ、STRINGIFY(_1 <_2) 'を求めているようではありません。小文字とトラッティングの'; 'は伝えています。 – MSalters

+0

プリプロセッサを使用するよりも、C++コードを文字列化する方法は他にありません:) –

+1

ランダムなC++コードの場合はTrueで、すべてのサブセットの場合はTrueです。たとえば、すべての10進数式のサブセットをストリング化するのは簡単です。同等のコードを等価とみなす方が簡単です。つまり、 'stringify(0x10)'が '16 'を生成する可能性があります。 – MSalters

関連する問題