3

(5.2.10 / 6)C ++ 03関数へのポインターは、別のタイプの関数へのポインターに明示的に変換できます。関数の定義で使用されている型と同じではない関数型(8.3.5)へのポインターを介して関数を呼び出す効果は未定義です。タイプ「pointertoT1」の右辺値をタイプ「pointertoT2」(T1とT2は関数型)に変換し、元のタイプに戻すことを除いて、元のポインター値が生成されます。このようなポインター変換の結果は指定されていません。 。[注:ポインター変換の詳細については、4.10も参照してください。]

以下は私がやろうとしていることですが、に変換fp1した結果がfp2元のポインターを生成することは明らかですが、同時に標準の表現は次の"The result of such a pointer conversion is unspecified"ようになります。それはどういう意味ですか?

int f() { return 42; }

int main()
{
    void(*fp1)() = reinterpret_cast<void(*)()>(f);

    int(*fp2)() = reinterpret_cast<int(*)()>(fp1);

    // Safe to call the function ?
    fp2();
}
4

3 に答える 3

5

はい、安全です。
reinterpret_castあるポインタを別のポインタにキャストできるようにするだけですが、安全性は保証されません。そのようなポインタを使用した結果は、元の型に型キャストされない限り指定されません。

前述の標準引用符は、ある型の関数ポインタを別の型に型キャストし、それを介して関数を呼び出そうとすると、結果が未定義になることを指定しています。

ただし、
reinterpret_cast型キャストされたポインターを元の型にキャストして戻すと、ポインターが適切に形成されることが保証されます。

あなたのコードは2番目を実行しようとするので、安全です。

于 2011-12-11T15:10:57.983 に答える
5

標準を誤解しています。「未指定」の部分は他の変換にのみ適用されます。

[特殊なケース] を除いて、そのようなポインタ変換の結果は規定されていません。

その[特別なケース]は、例のように、元の関数ポインター型に変換するものです。この特別なケースでは、変換により元のポインター値が生成されるため、例のように使用しても問題ありません。

他の変換の場合のみ、結果は規定されていません。

于 2011-12-11T15:18:41.743 に答える
4

うん、あなたは安全です。あなたがしていることは、「変換することを除いて...」の場合でカバーされます。

これが呼び出される理由は、関数ポインターを別のタイプの関数ポインターに渡すことができるようにするためです。したがって、次のように定義できます。

enum CallbackType {
    eFuncPtrVoidReturningVoid,
    eFuncPtrVoidReturningInt,
    // ... more as needed ...
};

class CallbackRecord
{
public:
    CallbackRecord(void (*cb)()): cbType(eFuncPtrVoidReturningVoid), cbFunc(cb) 
        {}
    CallbackRecord(int (*cb)()): cbType(eFuncPtrVoidReturningInt), 
        cbFunc(reinterpret_cast<void (*)()>(cb)) {}
    void operator()() const;
protected:
    CallbackType cbType;
    void (*cbFunc)();
};

void CallbackRecord::operator()() const
{
    switch(cbType)
    {
    case eFuncPtrVoidReturningVoid:
        (*cbFunc)();
        break;

    case eFuncPtrVoidReturningInt:
        while((*reinterpret_cast<int (*)()>(cbFunc))())
            ;
        break;
    }
}

「すべてのコールバックを返すようにする」と言うこともできますがint、コールバックタイプの数が2を超える場合は、呼び出し規約に準拠していないもののラッパーを作成する必要があります。これらの関数ポインター型キャストを許可すると、複数のコールバックタイプをサポートする代替手段が提供CallbackRecordされ、テンプレートに変換する必要がなくなります。また、メソッドを使用せずに、サブクラス化またはマーシャリングでswitch上記のステートメントを置き換えることもできvirtualます。

于 2011-12-11T15:10:32.747 に答える