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

Because the constructor of Derived is Derived(const T argD), so in your case it is Derived(int * const). This does not accept an const int*.

A "const (pointer to int)" is not a "(pointer to const int)".

于 2012-12-01T01:42:29.607 回答
1

您的示例中没有模板扣除。Derived<int*> d(p);专门将模板参数设置Tint*指向 int的指针)。在这种情况下,您的派生构造函数采用一个const T参数,该参数是一个指向 int 的 const 指针。我认为你的困惑是因为const int* p;没有声明一个指向 int 的 const 指针,而是声明了一个指向 const int的指针,它不是,也不能转换为一个指向 int 的 const 指针(前者允许你修改指向的值,而后者没有)。

请记住,C 和 C++ 声明通常是从变量名向外读取的,因此对于const int* p您从 开始p,向左看*,然后再向左看const intp指向 const int 的指针也是如此。是解密 C 声明的一个很好的指南,cdecl也是一个非常有用的工具。

你的例子的问题p是一个指向 const int的指针,但构造函数Derived<int*>需要一个指向 int 的 const 指针,因为Tis int*。这可能看起来令人困惑,但您可以认为const它具有比*类型声明更高的优先级。因此,const int *const应用于int然后*应用于整个事物中,创建指向 const intp的指针,而 for中,const 适用于,这实际上是指向int的const 指针const 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)不能重载,因为调用者是否将参数复制到常量变量中并不重要。

更具体地说,如果Tchar *(指向 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

If Tis const char*(pointer to a 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 pointer to a char) 那么所有的const T重载都是多余的,因为const T等价于TwhenT已经是 const。

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 回答