6

私は100個ほどのトランポリン機能を持っています。try/catch ブロック内でそれぞれを自動ラップすることが可能かどうかを知りたいです。

簡単な質問ではありませんので、あらかじめご了承ください。まず、(単純化された) コードで問題を説明し、次に、読者がどこにいるのかを理解できるように、以下でできる限り答えようとします。

Foo には関数ポインタ テーブルがあります。

EDIT : これはC 関数のポインタテーブルです。だからそれは受け入れることができましたstatic W::w
署名はこちら: http://svn.python.org/projects/python/trunk/Include/object.h

編集:ここでテストケースを試みました:

class Foo {
    Table table;
    Foo() {
        // Each slot has a default lambda.
        :
        table->fp_53 = [](S s, A a, B b)      -> int   {cout<<"load me!";};
        table->fp_54 = [](S s, C c, D d, E e) -> float {cout<<"load me!";};
        // ^ Note: slots MAY have different signatures
        //         only the first parameter 'S s' is guaranteed
    }

    // Foo also has a method for loading a particular slot:
    :
    void load53() { table->fp_53 = func53; }
    void load54() { table->fp_54 = func54; }
    :
}

特定のスロットが「ロード」されている場合、これはそれにロードされるものです:

int func53(S s, A a, B b) { 
    try{
        return get_base(s)->f53(a,b);
    } 
    catch(...) { return 42;} 
}

float func54(S s, C c, D d, E e) { 
    try{
        return get_base(s)->f54(c,d,e);
    } 
    catch(...) { return 3.14;} 
}

これらすべてを個別に定義する必要がないように、ラムダを使用してこれを達成しようとしていますfunc53。このようなもの:

class Foo {
    :
    void load53() { 
        table->fp_53 =
            [](S s, A a, B b)->int { return get_base(s)->f53(a,b); }
    }
    void load54() { 
        table->fp_54 =
            [](S s, C c, D d, E e)->float { return get_base(s)->f54(c,d,e); }
    }

ただし、これはエラーをトラップできません。return ステートメントの周りに try/catch を配置する必要があります。

try{ return get_base(s)->f53(a,b); } catch{ return 42; }

ただし、これにより多くの混乱が生じます。私ができればいいのですが:

return trap( get_base(s)->f53(a,b); )

trap私の質問は: この関数を (#define を使用せずに)記述する方法はありますか?


これは私がこれまでに思いついたものです:

これにより、必要なすべての情報が渡されると思います。

trap<int, &Base::f53>(s,a,b)

トラップの定義は次のようになります。

template<typename RET, Base::Func>
static RET 
trap(S s, ...) {
    try {
        return get_base(s)->Func(...);
    }
    catch {
        return std::is_integral<RET>::value ? (RET)(42) : (RET)(3.14); 
    }
}

これにより、非常にクリーンな構文が可能になる場合があります。

class Foo {
    :
    void load53() { table->fp_53 = &trap<int,   &Base::f53>; }
    void load54() { table->fp_54 = &trap<float, &Base::f54>; }
}

現時点では、いくつかの法律が違反されているかどうかさえわかりません。 table->fp_53有効な C 関数ポインターでなければなりません。

非静的メンバー関数 ( ) のアドレスを渡しても、&Base::f53>これはテンプレート パラメーターであり、署名には影響しないため、これに違反しません。trap

同様に、...C では varargs が許可されているので問題ありません。

これが実際に有効である場合、クリーンアップできますか?

私の考えは次のとおりです。

1) おそらく ... をパックとしてテンプレート パラメータに戻す必要があります。
2) トラップの戻り値の型を推測し、1 つのテンプレート パラメータを保存することは可能かもしれません。

3) そのBase::Funcテンプレート パラメータは不正な構文です。そして、それは合法的なものにさえ近づいていないと思います。これは、アプローチ全体を台無しにする可能性があります。

4

3 に答える 3

5
#include <utility>

template <typename T, T t>
struct trap;

template <typename R, typename... Args, R(Base::*t)(Args...)>
struct trap<R(Base::*)(Args...), t>
{    
    static R call(int s, Args... args)
    {
        try
        {
            return (get_base(s)->*t)(std::forward<Args>(args)...);
        }
        catch (...)
        {
            return std::is_integral<R>::value ? static_cast<R>(42)
                                              : static_cast<R>(3.14); 
        }
    }
};

使用法:

table->fp_53 = &trap<decltype(&Base::f53), &Base::f53>::call;
table->fp_54 = &trap<decltype(&Base::f54), &Base::f54>::call;

デモ


注: 転送参照自体ではありませんが、std::forward引き続き使用できます。Args

于 2015-01-07T14:53:00.477 に答える
4
template<typename RET, typename... Args>
struct trap_base {
    template<RET (Base::* mfptr)(Args...)>
    static RET 
    trap(S s, Args... args) {
        try {
            return (get_base(s).*mfptr)(args...);
        }
        catch (...) {
            return std::is_integral<RET>::value ? (RET)(42) : (RET)(3.14); 
        }
    }
};

使用法:

void load53() { table.fp_53 = &trap_base<int, int>::trap<&Base::f53>; }
void load54() { table.fp_54 = &trap_base<float, int, float>::trap<&Base::f54>; }

デモ

おそらく部分的な特殊化を使用して、RETand Argsfromdecltype(&base::f53)などを抽出することもできます。

于 2015-01-07T14:37:25.873 に答える
4

trap_genオンザフライで生成された関数への関数ポインタを返す関数であり、関数と同等ですtrap

使い方はこちら

table->fp_53 = trap_gen<>(Base::f53);
table->fp_54 = trap_gen<>(Base::f54);
...

Base::f53およびは、静的Base::f54メンバー関数 (または関数ポインター、または名前空間内のグローバル関数) です。

コンセプトの証明 :

#include <iostream>

template<typename R, class...A> 
R (*trap_gen(R(*f)(A...)))(A...)
{
    static auto g = f;

    return [](A... a) 
    {
        try {
            return g(a...);
        } catch (...) {
            return std::is_integral<R>::value ? static_cast<R>(42)
                                              : static_cast<R>(3.14); 
        }
    };
}

int add(int a, int b)
{
  return a+b;
}


int main() {
    int(*f)(int, int) = trap_gen<>(add);
    std::cout << f(2, 3) << std::endl;

    return 0;
}
于 2015-01-07T14:32:29.130 に答える