8

C++ 用語のランダムなシーケンスで構成された別の質問タイトルです!

通常は、 を実装して Callable クラスを作成しますoperator()。ただし、関数ポインターまたは参照型へのユーザー定義の変換を実装することで、これを行うこともできます。完全な転送を使用する代わりに、変換関数は、元の引数リストで呼び出される関数へのポインターを返すことができます。

struct call_printf {
    typedef int printf_t( char const *, ... );
    operator printf_t & () { return std::printf; }
};

http://ideone.com/kqrJz

私の知る限り、typedef上記は構文上の必要性です。変換関数の名前はtype-specifier-seqから形成され、 のような構成は許可されませんint (*)()。それにはabstract-declaratorが必要です。おそらくその理由は、そのような型名が複雑になり、オブジェクト名として使用される複雑な構造が解析しにくいためです。

変換関数もテンプレート化できますが、明示的に指定する場所がないため、テンプレート引数を推定する必要があります。(それは暗黙の変換のポイント全体を無効にします。)


質問 #1: C++03 では、関数変換演算子のテンプレートを指定する方法がありませんでしたか? テンプレート引数を解決する (つまり、推測されたコンテキストで名前を付ける) 方法が、受け入れ可能な関数ポインター型でないように見えます。

これは、C++11、§13.3.1.1.2/2 [over.call.object] からの同等の参照です。C++03 と実質的に同じです。

さらに、次の形式の T で宣言された非明示的な変換関数ごとに、

operator conversion-type-id () cv-qualifier attribute-specifier-seqopt;

ここで、cv-qualifierは cv と同じ cv-qualification、または cv より大きい cv-qualification でありconversion -type-idは「R を返す (P1,...,Pn) の関数へのポインター」型を示します。または型「R を返す (P1,...,Pn) の関数へのポインタへの参照」、または型「R を返す (P1,...,Pn) の関数への参照」、一意の名前 call-function とフォームを持つ

R call-function ( conversion-type-id F, P1 a1, ... ,Pn an) { return F (a1,... ,an); }

も候補関数と見なされます。同様に、代理呼び出し関数は、T の基本クラスで宣言された各非明示的な変換関数の候補関数のセットに追加されますが、その関数が別の介在する宣言によって T 内に隠されていなければなりません。


質問 #2: C++11 では、デフォルトのテンプレート引数を使用してそのような変換を指定できますか? これは SFINAE に役立ちます。上記の例との唯一の違いは、conversion-type-idがインスタンス化後の関数参照のみを表すことです。これは、依存型であるためです (不変性にもかかわらず)。これにより GCC がトリップし、メンバー テンプレートがスキップされます。

enum { call_alternate = true; }

struct call_switch {
    template< bool en = call_alternate >
    operator typename std::enable_if< en, decltype( fn_1 ) & >::type ()
        { return fn_1; }

    template< bool en = ! call_alternate >
    operator typename std::enable_if< en, decltype( fn_2 ) & >::type ()
        { return fn_2; }
};

エイリアス テンプレートもあります。競合の宣言がある §14.5.7/2 の例を考えると、エイリアス置換はインスタンス化の前に発生するようですprocess。GCC 4.7 では、このコードは少なくとも宣言をインスタンス化しますが、奇妙な「候補は 2 つの引数を期待し、2 つが提供されます」というエラーを生成します。

template< typename t >
using fn_t = void (&)( t );

struct talk {
    template< typename t >
    operator fn_t< t >() { return fn; }
};

int main() {
    talk()( 3 );
}
4

1 に答える 1

3

質問1:C ++ 03では、関数変換演算子テンプレートを指定する方法はありませんでしたか?受け入れ可能な関数ポインタ型でテンプレート引数を解決する(つまり、推測されたコンテキストで名前を付ける)方法がなかったようです。

はい、その通りです。

質問2:C ++ 11では、デフォルトのテンプレート引数を使用してそのような変換を指定できますか?

エイリアステンプレートを使用することもできますが、代理呼び出し関数を作成するためにそのような変換関数テンプレートを使用することはできません。それ以外の場合は、暗黙的な変換でクラスオブジェクトを関数ポインタに変換するために使用できます。

エイリアステンプレートもあります。プロセスの宣言が競合する§14.5.7/2の例を考えると、インスタンス化の前にエイリアス置換が発生するようです。GCC 4.7では、このコードは少なくとも宣言をインスタンス化しますが、その後、奇妙な「候補者は2つの引数を期待し、2つは提供されます」というエラーを生成します。

はい、これはhttps://groups.google.com/forum/?fromgroups#!topic/comp.std.c++/lXLFBcF_m3cです(そしてDR395の閉鎖を引き起こしました)が、そのような変換関数テンプレートは次のような場合に機能しますがvoid(&p)() = yourClassObject、サロゲート関数が呼び出されたときにクラスオブジェクトが変換される固定の非依存型を変換関数が提供する必要があるため、サロゲート呼び出し関数では機能しませんが、変換関数テンプレートはそのような型を提供しません通常(template<typename = int> operator Identity<void(*)()>();脇のような奇妙なもの...)。

GCCは、依存型がまだ存在する候補を誤って生成し、call-function(void (&)( t ), t)その候補を呼び出そうとして、その不変条件に違反する可能性があると思います(これは、奇妙なエラーメッセージを説明する可能性があります-} else { ... }予期せずどこかにヒットする可能性があります)。

于 2012-06-13T20:56:59.110 に答える