3

私はこの機能を持っています:

template <typename T, void (T::*pf)()>
void call(T& t)
{
    (t.*pf)();
}

foo適切なシグネチャ (たとえば ) を持つメソッドを持つクラスがある場合bar、このように呼び出すことができ、call<foo, &foo::bar>();問題ありません。ただし、gcc と msvc は、このように呼び出されたときに喜んでコンパイルしbarます。Clang は、2 番目のテンプレート パラメーターが無効であると文句を言います。テンプレート引数 ( )を入れると、すべてのツリーがコンパイルされます。constcall<const foo, &foo::bar>()constvoid (T::*pf)() const

constさて、これは大きな問題ではありませんが、テンプレート引数にこれを惨めに書く必要がなければ、私のコードはずっときれいになります。

したがって、基本的な質問は次のとおりです。標準はこれについて何と言っていますか? これはclangのバグですか、それともgccとmsvcはそのようにクールなのでスライドさせているだけですか?

PS 完全な再現プログラムへのリンクは次のとおりです: http://codepad.org/wDBdGvSN

4

1 に答える 1

2

メソッドのconst-nessは、その「シグネチャ」の一部です。したがって、メンバーへのポインタを定義して使用する適切な方法は次のとおりです。

R (Obj::*)(Args)       // for non-const member
R (Obj::*)(Args) const // for const member

constメンバーは非constオブジェクトで呼び出すことができますが、。の場合はそうではないことに注意してくださいR (const Obj::*)(Args)

これを解決する方法は、「呼び出しラッパー」を定義することにより、そのような関数ポインターを抽象化することです。

template<typename O, void (O::* f)()>
struct NonConstFunc
{
    static void call(O* o)
    {
        (o->*f)();
    }
};

template<typename O, void (O::* f)() const>
struct ConstFunc
{
    static void call(O* o)
    {
        (o->*f)();
    }
};

次に、次の方法で使用できます(ここでは抽象化が行われます)。

template<typename Obj, typename Function>
void call(Obj* o)
{
    Function::call(o);
}

ここに実例があります。

これが主なアイデアです。constユーザーコードを変更することなく、メソッドがそうであるかどうかの自動検出で拡張できます。

于 2013-03-08T12:41:31.717 に答える