1

次のように複数のテンプレートを使用することはできないようです。

template <typename T>
template <T value>
void printValueAsInteger()
{
    printf("value as integer is %i\n", (int) value);
}

次のように呼び出すことができます。

printValueAsInteger<123>();

次のエラー メッセージが表示されますtoo many template-parameter-lists

template <typename T, T value>withを使用すると機能printValueAsInteger<int, 123>()しますが、その場合は型を明示的に指定する必要があります。printValueAsInteger<123>()印刷するようにするにはどうすればよいvalue as integer is 123ですか?

編集:

これが必要な理由をより具体的に説明します。私の目標は、メンバー関数を関数ポインターとして渡すことであり、テンプレートを使用してラップすることを考えました。

template <typename T>
template <T* instance, void (T::*method)()>
void wrappedMethod()
{
    (instance->*method)();
}
void callFunction(void (*function)())
{
    (*function)();
}

そして、次のように渡します。

Base *instance = new Derived;
callFunction(&wrappedFunction<instance, Base::method>);

編集:

エラー、おそらく実行時定義の変数をテンプレート引数として使用すべきではない (そして使用できない) ことに気付きました。私は現在、そうでなければテンプレート引数でインスタンス化されたクラスを使用し、そのクラスを使用するテンプレート関数を作成して、それを回避しようとしています。またはそのようなもの。いいえ、うまくいきません。

callFunction はサードパーティ API の一部であるため、署名を変更できないことに注意してください。

やっと!

ヘッダーに以下を入れます。

class Callable
{
public:
    virtual ~Callable() { }
    virtual void call() { }
};

typedef void (*functionPtr)();
extern unsigned nextMethodId;
extern functionPtr wrappedMethods[];
extern Callable *boundMethods[];

template <unsigned I>
class MethodWrapper
{
public:
    static void function();
};

template <typename T>
class Method : public Callable
{
public:
    Method(T* instance, void (T::*method)());
    virtual void call();
private:
    T* instance;
    void (T::*method)();
};

template <typename T>
Method<T>::Method(T* instance, void (T::*method)())
    : instance(instance), method(method) {
}

template <typename T>
void Method<T>::call()
{
    if (instance && method)
        (instance->*method)();
}

template <typename T>
static functionPtr bindMethod(T* instance, void (T::*method)())
{
    boundMethods[nextMethodId] = new Method<T>(instance, method);
    return (void (*)()) wrappedMethods[nextMethodId++];
}

そしてこれをソースファイルに:

#include "<insert header name here>.h"

unsigned nextMethodId = 0;
functionPtr wrappedMethods[] = {
    &MethodWrapper<0>::function,
    &MethodWrapper<1>::function,
    &MethodWrapper<2>::function
};
Callable *boundMethods[sizeof(wrappedMethods) / sizeof(functionPtr)];

template <unsigned I>
void MethodWrapper<I>::function()
{
    boundMethods[I]->call();
}

次のように使用できます。

Base *instance = new Derived;
void (*function)() = bindMethod(instance, &Base::method);
callFunction(function);

メソッドの派生インスタンスのバージョンが正常に呼び出されます。残念ながら、バインドできるメソッドの数は固定されています (この例では 3 つ) が、簡単に拡張できます。

4

2 に答える 2

1

単純な変換では、ランタイム値が、インスタンス ポインターとメンバー関数へのポインターを保持するファンクターのコンストラクターへの引数になります。使用場所での構文は次から変更されます。

Base *instance = new Derived;
callFunction(&wrappedFunction<instance, Base::method>);

に:

callFunction( WrappedFunction<Base,&Base::method>( instance ) );

型の実装WrappedFunctionは実際には単純なので、演習として残します。このアプローチの主な変更点は、 への引数が関数ポインタではなくfunctorcallFunctionになることです。

C++11 (またはブースト付き) では、最も簡単な方法は、何もコーディングせずに利用可能なリソースを使用することです。の署名を次のように変更しますcallFunction

void callFunction( function<void ()> f );

そしてbind、電話をかけるために使用します:

callFunction( bind( &Base::method, instance ) );
于 2012-07-22T21:44:45.980 に答える
0

最初の例ではint、テンプレート パラメーターのタイプとして次のように指定できます。

template <int I>
void printValueAsInteger()
{
    printf("value as integer is %i\n", I);
}

テンプレートはコンパイル時に使用されるため、編集では、既に述べたようにランタイム定義の変数を使用できません。std::bindandを使用すると、次のstd::functionように簡単になります。

void callFunction(std::function<void()> f)
{
    f();
}

Base *instance = new Derived;
callFunction(std::bind(&Base::method, instance));

コメントの後

私が考えることができる唯一の方法は、あなたのメンバーを機能させることですstatic

callFunction(&Base::method); // Okay if the method is declared static

または、グローバル インスタンスでグローバル ラッパー関数を使用します。

Base *instance = new Derived; // Global
void wrapperFunction()
{
    instance->method();
}

callFunction(wrapperFunction);
于 2012-07-22T20:52:16.977 に答える