6


0

void(U :: *)(void)はどういう意味ですか?

Boostでの `is_class`テンプレートの実装を見ていて、簡単に解読できない構文に遭遇しました。

    template  static ::boost::type_traits::yes_type is_class_tester(void(U::*)(void));
    template  static ::boost::type_traits::no_type is_class_tester(...);
上記の `void(U

)(void)`を解釈するにはどうすればよいですか? 私はCに精通しているため、 `void()(void)`に多少似ていますが、 `U ::`がポインタを変更する方法がわかりません。 誰も手伝ってくれる?

ありがとう

5 Answer


13


」はポインターを示します。これは、「 p」と記述することでその内容にアクセスできるためです。 `U

`はクラス `U`のメンバーへのポインタを示します。 その内容にアクセスするには、「u。 p」または「pu→ * p」(「u」は「U」のインスタンス)を記述します。

したがって、あなたの例では、 `void(U

*)(void)は、引数を取らず値を返さない関数である `U *のメンバーへのポインター*です。

例:

class C { void foo() {} };

typedef void (C::*c_func_ptr)(void);

c_func_ptr myPointer = &C::foo;


3


Uから始めて、裏返しで作業します。

宣言された型は、void引数を取り、voidを返すクラスUからのメンバー関数へのポインターです。


3


あなたは正しい、それは関数ポインタに似ています。 むしろ、これはメンバー関数へのポインタであり、メンバーはクラス「U」のものです。

メンバー関数は、インスタンスなしでは呼び出せないため、暗黙の `this`ポインターを持っているため、型の違いが必要になります。 テンプレートを削除すると、少し簡単になります。

struct foo
{
    void bar(void);
};

`void(*)(void)`は、クラスのインスタンスを通信する方法がないため、実行しません。 むしろ、次のものが必要です。

void (foo::*)(void)

この関数ポインターが `foo`のインスタンスを必要とすることを示します。

'' '' '

価値があるものとして、次のように使用します。

typedef void (foo::*func_ptr)(void);

foo f;
foo* fp = &f;
func_ptr func = &foo::bar;

(f.*func)();
(fp->*func)();


3


クラスUのメンバー関数へのポインターです。 それは非常に似ています

無効(*)(無効)

ただし、クラスUのメンバー関数を指します。


0


私はこれとまったく同じ質問をするつもりでしたが、すでに質問されています。 残念ながら、既存の回答のどれもが実際に質問に答えませんでした。 少なくとも私には。 困惑させなければなりませんでした。 私はOPと同じ質問に加えていくつかの質問をしたかった。 私の質問:WTFはこの `is_class_tester(void(U

*)(void))`のものであり、SFINAE(置換失敗はエラーではありません)のコンテキストでこのコンストラクトはどのように機能しますか?

いくらか簡略化して、Boostは次のように構造を使用します。

template
char is_class_tester (void (U::*)(void));

template
TypeBiggerThanChar is_class_tester (...);

template
struct IsClass {
   static const bool value = sizeof (is_class_tester(0)) == 1;
};

いくつかの観察:

  1. これらの関数テンプレートは、実際には関数テンプレートではありません。 彼らです オーバーロードされた関数テンプレートのペアの宣言を転送するだけです。 関数テンプレート自体は決して定義されません。 これを理解し、テンプレートを定義する必要なくこれがどのように機能するかを理解することは、この構成を理解する上で重要な要素の1つです。

  2. この最初の関数テンプレートの使用方法について説明した回答 ボートに乗り遅れた。 定義が存在しないため、この関数テンプレートは使用できません。

  3. その難解な議論のおかげで、2つの最初の 関数テンプレートは、タイプ `T`がクラスである場合にのみ意味を持ちます。 基本型とポインターにはメンバー関数がありません。 最初の宣言は、非クラス型の無効な構文です。

  4. オーバーロードされた2番目の関数テンプレートとは対照的に、 これはすべてのテンプレートパラメーターの有効な構文であり、関数(存在する場合)は、その可変引数のおかげでスローされた引数を取ります。

  5. 引数。 (脇:これはぼんやりと私のお気に入りを連想させる 適切にフォーマットされたユーザー入力があれば、世界のあらゆる問題を解決できる1行のCプログラム。

  6. 関数テンプレート宣言は関数として使用できませんが、 宣言は、戻り型に関するクエリなどの単純なコンパイル時クエリで使用できます。 この種のクエリには実際の定義は必要ありません。 プロトタイプのみが必要です。

  7. これは、クラステンプレート `IsClass`が定義するものです

    コンパイル時定数 `IsClass

    value`。

    それで、 `IsClass

    value`はその値をどのように取得し、コンパイル時にどのようにそれを行うのでしょうか? コンパイラは、 `sizeof(is_class_tester(0))`の意味を理解するか、試行をあきらめる必要があります。 型 `SomeType`がクラスであるかどうかに基づいて、2つのケースを調べる必要があります。

    ケース1: SomeType`はクラスです。 +ここでは、両方のテンプレート宣言が有効な構文であるため、コンパイラには2つの実行可能な候補があります。 コンパイラは最初の関数テンプレートを使用できますが、選択する必要があるのは、選択規則では可変個の関数が選択において最低の優先度を取得するためです。 この選択された関数は文字を返します。 sizeof(char)は1であることが保証されているため、 `SomeType`がクラスの場合、 IsClass

    value`はtrueになります。

    ケース2: SomeType`はクラスではありません。 +ここにSFINAEがあります。 最初の関数テンプレート宣言は無効な構文です。 SFINAEのため、コンパイラはここでjustめることはできません。 代替手段を探し続ける必要があり、2番目の関数テンプレート宣言が法案に適合します。 唯一の実行可能な関数は、定義を省略した「TypeBiggerThanChar」を返しますが、うまくいけば明白です。 必要なのは、このことをsizeof()だけです。 文字よりも大きいため、 `SomeType`がクラスではない場合、 IsClass

    value`はfalseになります。