3

コードがコンパイルされない理由を誰かが説明できますか?

template<class T, class DER>
struct Base {
  T a;
  Base(const T argB) : a(argB){}
};

template<class T>
struct Derived : Base<T, Derived<T> > {
  Derived(const T argD) : Base<T, Derived<T> >(argD){}
};

int main() {
  int val = 10;
  const int *p = &val;
  /* this was in the original question
  Derived<int*> d(p); // breaks, but compiles with Derived<const int*> d(p);
  */
  Derived d(p); // fails, but Derived<const int*> d(p); compiles
}

int*エラーメッセージは、からへの変換がないことconst int*です。私が見るように、それTはによる置換である可能性がint*あり、その場合、コンストラクターDerivedはその引数をaとして受け取り、 。const int*でベースを呼び出しますconst int*。それでは、なぜ絶え間ない定量化が失われるのでしょうか。

テンプレート引数の推論がどのように機能するかをはっきりと理解していません。私は、それがどのように機能するかについての明快でありながら厳密で網羅的な説明を見つけることができませんconstでし*&。つまりa 、これらのさまざまなケースでタイプが推測されるものです。

 Foo(T& a)
 Foo(T  a)
 Foo(T* a)
 Foo(const T a)
 Foo(const T*a)
 Foo(const t&a)

いつaですか

  • オブジェクト、
  • ポインタと
  • 配列。
4

2 に答える 2

4

のコンストラクタDerivedDerived(const T argD)であるため、あなたの場合はですDerived(int * const)。これはを受け入れませんconst int*

「const(intへのポインタ)」は「(const intへのポインタ)」ではありません。

于 2012-12-01T01:42:29.607 に答える
1

あなたの例にはテンプレートの控除はありません。Derived<int*> d(p);具体的には、テンプレートパラメータをTint*intへのポインタ)に設定します。派生コンストラクターは、この場合はintへのconstポインターconst Tであるパラメーターを取ります。あなたの混乱は、 intへのconstポインターを宣言せず、代わりにintへのconstポインターではなく、それに変換できないconst intへのポインターを宣言しているためだと思います(前者は、ポイントされた値を変更できますが、後者はしません)。const int* p;

CおよびC++宣言は通常、変数名から外側に向かって読み取られることに注意してください。したがって、const int* pから始めてp、左に移動して表示*し、さらに左に移動して参照してください。constintへのポインタもconst int同様です。これはC宣言の解読に関する優れたガイドであり、cdeclも非常に便利なツールです。p

この例の問題は、 const intへpのポインターですが、のコンストラクターは、であるため、intへのconstポインターを取ります。これは紛らわしいように思えるかもしれませんが、型宣言よりも優先順位が高いと考えることができます。したがって、ではconst intへのポインタを作成する全体に適用され、次に適用されますが、の場合、constはに適用されます。これは実際にはintへのconstポインタになります。Derived<int*>Tint*const*const int *constint*pconst TTint*const T argDargD

これと同じアイデアを使用すると、すべてのFoo例を簡単に解読できます。

Foo(T& a)       // a is a reference to a value of type T
Foo(T  a)       // a is a value of type T
Foo(T* a)       // a is a pointer to a value of type T
Foo(const T a)  // a is a constant value of type T
Foo(const T* a) // a is a pointer to a constant value of type T
Foo(const T& a) // a is a reference to a constant value of type T

一般Foo(T a)Foo(const T a)、引数が定数変数にコピーされるかどうかは呼び出し元にとって重要ではないため、オーバーロードすることはできません。

より具体的には、if Tis char *(charへのポインタ)

Foo(char *&a)       // a is a reference to a pointer to a char
Foo(char *a)        // a is a pointer to a char (*)
Foo(char **a)       // a is a pointer to a pointer to a char
Foo(char *const a)  // a is a constant pointer to a char (cannot overload with (*))
Foo(char *const *a) // a is a pointer to a constant pointer to a char
Foo(char *const &a) // a is a reference to a constant pointer to a char

もしそうならTconst char*const charへのポインタ)物事はほとんど同じです

Foo(const char *&a)       // a is a reference to a pointer to a const char
Foo(const char *a)       // a is a pointer to a const char (*)
Foo(const char **a)       // a is a pointer to a pointer to a const char
Foo(const char *const a)  // a is a constant pointer to a const char (cannot overload with (*))
Foo(const char *const *a) // a is a pointer to a constant pointer to a const char
Foo(char *const &a) // a is a reference to a constant pointer to a const char

Tis char* const(文字へのconstポインタ)の場合、がすでにconstである場合と同等であるため、すべてのオーバーロードは冗長const Tです。const TTT

Foo(char *const &a) // a is a reference to a const pointer to a char (+)
Foo(char *const a)  // a is a const pointer to a char (*)
Foo(char *const *a) // a is a pointer to a const pointer to a char (^)
Foo(char *const a)  // a is a const pointer to a char (same as (*))
Foo(char *const *a) // a is a pointer to a const pointer to a char (same as (^))
Foo(char *const &a) // a is a reference to a const pointer to a char (same as (+))
于 2012-12-01T03:11:53.417 に答える