2013-03-27 12 views
5

Czy mogę przekonwertować wyrażenie "Wzbogać Phoenix" na reprezentatywny ciąg C++? Mogłem:Czy mogę uszeregować wyrażenie "Zwiększ Phoenix"?

stringify(_1<_2); 

który może następnie wytworzyć ciąg zawierający coś takiego:

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

Doceniam ten przykład ma jakieś ostre krawędzie, ale zastanawiam się, czy coś w tym kierunku podjęto próbę?

+1

Dlaczego chcesz to zrobić? –

+0

Tricky. 'stringify (_1 <2);' to _almost_ to samo, ale ma całkiem inne rozwinięcie. (funkcja unarna) – MSalters

+1

Nie rozumiem pytania. '_1 <_2' definiuje funkcję, która przyjmuje dwa argumenty i zwraca' bool'. Twój 'foo' definiuje funkcję, która przyjmuje dwa argumenty i zwraca' x' lub 'y'. Jaka jest relacja między tymi dwoma? –

Odpowiedz

3

Za pomocą transformacji eval można znaleźć here jako "inspirację".

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

Wygląda interesująco, przejdę później. – user2023370

+0

Bardzo ładnie wykonane. – user2023370

-2

Strojenie jest funkcją preprocesora - można tylko ustrukturyzować tokeny, które są dostępne dla preprocesora. Obsługa typów (włącznie z rozszerzeniem typu i wyrażenia) jest wykonywana przez kompilator, który uruchamia po preprocesorze, więc nie ma możliwości wykonania żądanej struktury.

+1

Myślę, że bierzesz "stringify" zbyt dosłownie. Nie widzę założenia, że ​​powinien to zrobić preprocesor. To nie jest tak, że on prosi o "STRINGIFY" (_1 <_2) w końcu - małe litery i tryling ";" mówią. – MSalters

+0

Nie ma innego sposobu na stringify kodu C++ niż przy użyciu preprocesora :) –

+1

Prawda dla losowego kodu C++, nie dla wszystkich podzbiorów. Na przykład, proste jest ciągiowanie podzbioru wszystkich wyrażeń dziesiętnych. Jest jeszcze łatwiej, jeśli weźmiesz pod uwagę równoważny kod równy, tj. Jeśli 'stringify (0x10)' może wytworzyć '16'. – MSalters