-1

コンパイルして正常に実行される完全なコードは次のとおりです。

 # include <iostream>

using namespace std;

template<class T> class A { };

template<int i> class B { };

class C {
   public:
      int x;
};

class D {
   public:
      C y;
      int z;
};

template<class T> void f (T)          { cout << "T" << endl; };
template<class T> void f1(const T)    { cout << "const T" << endl; };
temlate<class T> void f2(volatile T) { cout << "volatile T" << endl;  };
template<class T> void g (T*)         { cout << "T*" << endl; };
template<class T> void g (T&)         { cout << "T&" << endl; };
template<class T> void g1(T[10])      { cout << "T[10]" << endl;};
template<class T> void h1(A<T>)       { cout << "A<T>" << endl; };

void test_1() {
   A<char> a;
   C c;

   f(c);   f1(c);   f2(c);
   g(c);   g(&c);   g1(&c);
   h1(a);
}

template<class T>          void j(C(*)(T)) { cout << "C(*) (T)" << endl; };
template<class T>          void j(T(*)())  { cout << "T(*) ()" << endl; }
template<class T, class U> void j(T(*)(U)) { cout << "T(*) (U)" << endl; };

void test_2() {
   C (*c_pfunct1)(int);
   C (*c_pfunct2)(void);
   int (*c_pfunct3)(int);
   j(c_pfunct1);
   j(c_pfunct2);
   j(c_pfunct3);
}

template<class T>          void k(T C::*) { cout << "T C::*" << endl; };
template<class T>          void k(C T::*) { cout << "C T::*" << endl; };
template<class T, class U> void k(T U::*) { cout << "T U::*" << endl; };


void test_3() {
   k(&C::x);
   k(&D::y);
   k(&D::z);
}

template<class T>     void m(T (C::*)() )
   { cout << "T (C::*)()" << endl; };
template<class T>     void m(C (T::*)() )
   { cout << "C (T::*)()" << endl; };
template<class T>     void m(D (C::*)(T))
   { cout << "D (C::*)(T)" << endl; };
template<class T, class U>  void m(C (T::*)(U))
   { cout << "C (T::*)(U)" << endl; };
template<class T, class U>  void m(T (C::*)(U))
   { cout << "T (C::*)(U)" << endl; };
template<class T, class U>  void m(T (U::*)() )
   { cout << "T (U::*)()" << endl; };
template<class T, class U, class V> void m(T (U::*)(V))
   {
 cout << "T (U::*)(V)" << endl; };

void test_4() {
   int (C::*f_membp1)(void);
   C (D::*f_membp2)(void);
   D (C::*f_membp3)(int);
   m(f_membp1);
   m(f_membp2);
   m(f_membp3);

   C (D::*f_membp4)(int);
   int (C::*f_membp5)(int);
   int (D::*f_membp6)(void);
   m(f_membp4);
   m(f_membp5);
   m(f_membp6);

   int (D::*f_membp7)(int);
   m(f_membp7);
}

template<int i> void n(C[10][i]) { cout << "E[10][i]" << endl; };
template<int i> void n(B<i>)     { cout << "B<i>" << endl; };

void test_5() {
   C array[10][20];
   n(array);
   B<20> b;
   n(b);
}

template<template<class> class TT, class T> void p1(TT<T>)
   { cout << "TT<T>" << endl; };
template<template<int> class TT, int i>     void p2(TT<i>)
   { cout << "TT<i>" << endl; };
template<template<class> class TT>          void p3(TT<C>)
   { cout << "TT<C>" << endl; };

void test_6() {
   A<char> a;
   B<20> b;
   A<C> c;
   p1(a);
   p2(b);
   p3(c);
}

int main() { test_1(); test_2(); test_3(); test_4(); test_5(); test_6(); }

私の人生と脳のすべての問題の原因は次のとおりです。test_3()

読みやすくするための関連コード:

class C {
   public:
      int x;
};

template<class T>          void k(T C::*) { cout << "T C::*" << endl; };
template<class T>          void k(C T::*) { cout << "C T::*" << endl; };
template<class T, class U> void k(T U::*) { cout << "T U::*" << endl; };

void test_3() {
   k(&C::x);
   k(&D::y);
   k(&D::z);
}

私を最も悩ませているこのコード:

template<class T>          void k(T C::*)

つまり、それはどのような構文であり、それがどのようにうまく機能するかということです。なぜTC::*またはC前にT::*その逆が必要なのか。私と誰かがその構文がなぜそんなに奇妙なのか、そしてそれがどのように機能するのか教えてください。

私はC++を初めて使用し、C#、C、およびOOPで優れた経験を持っています。上記のコード行をよりクリーンな方法で記述するための構文と代替の方法/構文を説明してください。前もって感謝します。

4

2 に答える 2

5

T C::*タイプを持つクラスの任意のメンバーへのポインターをC宣言しますT(ここTで、はtemplate-parameterです)。パラメータには名前がないため、関数内で使用することはできません。過負荷解決にのみ使用されます。同じことがとにも当てはまりC T::*ますT U::*

それが機能する理由は、インスタンス化から見ることができます。

k(&C::x);

これは最初のオーバーロードに解決され、タイプがであるため、タイプTがであると推測されます。intC::xint

k(&D::y);

D::yはタイプであるため、これは2番目のオーバーロードに解決されCます。Tタイプがあると推測されますD

k(&D::z);

これは3番目の過負荷に解決されます。はタイプであるため、タイプがあると推測されT、タイプがあると推測されます。DUintD::zint

全体として、この例はおそらく人々を混乱させるように設計されたと思います。それがチュートリアルとして意図されていた場合、それはより良い命名といくつかのコメントで行うことができます。

于 2012-12-07T10:45:02.013 に答える
2

そのプログラムは、過負荷解決のさまざまなケースを示しているようです。文法を練習しているだけです。

T C::*Cタイプが。のクラスのメンバーを参照するオブジェクトを宣言しますT。クラスのメンバーを参照するには、クラスのタイプとメンバーのタイプの両方が必要です。::宣言の演算子は、初期化で使用される演算子に対応しています。

T C:: *x = & C::q;

ここで、ポインター宣言子は、ポインターの宣言と初期化と同様に*、address-of演算子と一致します。クラスメンバーを参照するオブジェクトは、構文ではポインターのように見えるため、メンバーへのポインターと呼ばれます。(しかし、内部では、それはまったくポインターではありません。)&T *y = & r;

メンバーへのポインタが使用されることはめったになく、C ++に慣れるまで、メンバーを無視しても問題ありません。

これは特にテンプレートとは関係ありません。プログラムは2つの基になる型Tとを含むため、メンバーへのポインタを使用しているだけですC。テンプレートの過負荷解決では、署名のTとCの具体的な方法に基づいて関数の1つが選択されます。引数タイプのT部分とC部分を一致させます。

于 2012-12-07T10:50:43.277 に答える