web-dev-qa-db-ja.com

PythonのようなC ++デコレーター

pythonスタイルのように、C++で関数またはメソッドを装飾する方法はありますか?

@decorator
def decorated(self, *args, **kwargs):
     pass

マクロを使用する例:

DECORATE(decorator_method)
int decorated(int a, float b = 0)
{
    return 0;
}

または

DECORATOR_MACRO
void decorated(mytype& a, mytype2* b)
{
}

出来ますか?

30
Artem Selivanov

std::function 提案するソリューションのビルディングブロックのほとんどを提供します。

これが私の提案する解決策です。

#include <iostream>
#include <functional>

//-------------------------------
// BEGIN decorator implementation
//-------------------------------

template <class> struct Decorator;

template <class R, class... Args>
struct Decorator<R(Args ...)>
{
   Decorator(std::function<R(Args ...)> f) : f_(f) {}

   R operator()(Args ... args)
   {
      std::cout << "Calling the decorated function.\n";
      return f_(args...);
   }
   std::function<R(Args ...)> f_;
};

template<class R, class... Args>
Decorator<R(Args...)> makeDecorator(R (*f)(Args ...))
{
   return Decorator<R(Args...)>(std::function<R(Args...)>(f));
}

//-------------------------------
// END decorator implementation
//-------------------------------

//-------------------------------
// Sample functions to decorate.
//-------------------------------

// Proposed solution doesn't work with default values.
// int decorated1(int a, float b = 0)
int decorated1(int a, float b)
{
   std::cout << "a = " << a << ", b = " << b << std::endl;
   return 0;
}

void decorated2(int a)
{
   std::cout << "a = " << a << std::endl;
}

int main()
{
   auto method1 = makeDecorator(decorated1);
   method1(10, 30.3);
   auto method2 = makeDecorator(decorated2);
   method2(10);
}

出力:

Calling the decorated function.
a = 10, b = 30.3
Calling the decorated function.
a = 10

[〜#〜] ps [〜#〜]

Decoratorは、関数呼び出しを行う以外に機能を追加できる場所を提供します。 std::functionへの単純なパススルーが必要な場合は、以下を使用できます。

template<class R, class... Args >
std::function<R(Args...)> makeDecorator(R (*f)(Args ...))
{
   return std::function<R(Args...)>(f);
}
26
R Sahu

これが私の試みです。 C++ 14で動作します(一般的なラムダと戻り値の型の推定)。

#include <iostream>
#include <functional>

/* Decorator function example,
   returns negative (! operator) of given function
*/
template <typename T>
auto reverse_func(T func)
{
    auto r_func =
    [=](auto ...args)
    { 
        return !func(args...); 
    };

    return r_func; 
}

/* Decorator function example,
   prints result of given function before it's returned
*/
template <typename T>
auto print_result_func(T func)
{
    auto r_func = 
    [=](auto ...args)
    {
        auto result = func(args...);
        std::cout << "Result: " << result << std::endl;
        return result;
    };

    return r_func;
}

/* Function to be decorated example,
   checks whether two given arguments are equal
*/
bool cmp(int x, int y)
{
    return x == y;
}

/* Decorator macro */
#define DECORATE(function, decorator) \
    decorator<decltype(function)>(function)

int main()
{
    auto reversed = DECORATE(cmp, reverse_func);
    auto print_normal = DECORATE(cmp, print_result_func);
    auto print_reversed = DECORATE(reversed, print_result_func);
    auto print_double_normal = DECORATE(print_normal, print_result_func);
    auto print_double_reversed = DECORATE(print_reversed, print_result_func);

    std::cout << cmp(1,2) << reversed(1,2) << std::endl;
    print_double_normal(1,2);
    print_reversed(1,2);
    print_double_reversed(1,2);
}
9
thorhunter

トークン貼り付け前処理演算子##を使用して、このタイプのいくつかの制限された機能を取得できます。 https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html を参照してください。 Cでは、すべての関数名はリンク時に定義する必要があるため、関数はPythonのように変換できるオブジェクトではありません。したがって、Pythonデコレータは便利で優れたスタイルですが、Cではそのようなトリックは使用する場合は控えめに使用する必要があります。

2
Paul Cornelius