有人可以解释为什么代码无法编译。
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
的构造函数将其参数作为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
时
答案 0 :(得分:4)
因为Derived
的构造函数是Derived(const T argD)
,所以在您的情况下它是Derived(int * const)
。这不接受const int*
。
“const(指向int的指针)”不是“(指向const int的指针)”。
答案 1 :(得分:1)
您的示例中没有模板推断。 Derived<int*> d(p);
专门将模板参数设置为T
到int*
(指向int 的指针)。在这种情况下,派生的构造函数采用const T
参数,该参数是 const指向int 的指针。我认为你的困惑是因为const int* p;
没有声明一个指向int 的 const指针,而是声明一个指向const int 的指针,它不是,并且不能被转换to,一个 const指向int 的指针(前者允许你修改指向的值,而后者则没有)。
请记住,C和C ++声明通常从变量名称向外读取,因此const int* p
从p
开始,向左走,看*
然后向左走,看看const int
,所以p
是指向const int的指针。 Here是解密C声明的好指南,cdecl也是一个非常有用的工具。
您的示例的问题是p
是指向const int 的指针,但Derived<int*>
的构造函数将 const指针指向int 因为T
是int*
。这可能看起来令人困惑,但您可以将const
视为在类型声明中具有比*
更高的优先级。因此,在const int *
中,const
适用于int
,然后*
适用于整个事情,使p
成为指向const int的指针而对于const T
,const适用于T
,实际上int*
因此const T argD
使argD
成为 const指针指向int
使用同样的想法,您的所有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)
不能重载,因为调用者是否将参数复制到常量变量中并不重要。
更具体地说,如果T
是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
如果T
是const 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
如果T
是char* const
(指向char的const指针),则所有const T
重载都是多余的,因为const T
等同于T
T
1}}已经是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 (+))