[英]Template argument deduction and const qualification
Could anyone explain why the code does not compile. 任何人都可以解释为什么代码不能编译。
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
}
The error message is that about no conversion from int*
to const int*
. 错误消息是没有从
int*
到const int*
转换。 As I see it T
can be substitues by int*
and in that case the constructor to Derived
receives its argument as a const int*
and invokes the base with const int*
. 我看到它
T
可以是由substitues int*
和在这种情况下,构造函数来Derived
接收其参数为const int*
和调用与碱const int*
。 Why then is the constant qulaification getting lost. 那么为什么不断的诽谤会丢失。
I clearly do not understand how template argument deduction works. 我显然不明白模板参数推导是如何工作的。 I have not been able to find any lucid but rigorous and exhaustive description of how it works when
const
, *
and &
are in play. 当
const
, *
和&
发挥作用时,我无法找到任何清晰但严谨而详尽的描述。 That is, what will a
get type deduced to in these various cases. 也就是说,什么都会
a
获取类型推断在这些各种情况。
Foo(T& a)
Foo(T a)
Foo(T* a)
Foo(const T a)
Foo(const T*a)
Foo(const t&a)
when a
is 当
a
是
Because the constructor of Derived
is Derived(const T argD)
, so in your case it is Derived(int * const)
. 因为
Derived
的构造函数是Derived(const T argD)
,所以在你的情况下它是Derived(int * const)
。 This does not accept an const int*
. 这不接受
const int*
。
A "const (pointer to int)" is not a "(pointer to const int)" . “const(指向int的指针)”不是“(指向const int的指针)” 。
There is no template deduction in your example. 您的示例中没有模板推断。
Derived<int*> d(p);
specifically sets the template parameter to T
to int*
( pointer to int ). 具体将模板参数设置为
T
to int*
( 指向int的指针 )。 Your derived constructor takes a const T
parameter which is a const pointer to int in this case. 派生的构造函数采用
const T
参数,在这种情况下是一个指向int的const指针 。 I think your confusion is because const int* p;
我认为你的困惑是因为
const int* p;
does not declare a const pointer to int , but instead declares a pointer to const int which is not, and cannot be converted to, a const pointer to int (the former lets you modify the pointed to value while the latter does not). 不会声明一个指向int的const指针 ,而是声明一个指向const int的指针,该指针不是,也不能转换为指向int的const指针 (前者允许您修改指向的值,而后者则不会)。
Remember that C and C++ declarations are generally read from the variable name outwards, so for const int* p
you start at p
, go left and see *
and then go farther left and see const int
, so p
is a pointer to a const int. 请记住,C和C ++声明通常从变量名称向外读取,因此对于
const int* p
,从p
开始,向左看并查看*
然后再向左看并看到const int
,所以p
是指向const int的指针。 Here is a good guide on deciphering C declarations and cdecl is also a very useful tool. 这是解密C声明的好指南, cdecl也是一个非常有用的工具。
The problem with your example is p
is a pointer to const int , but the constructor of Derived<int*>
takes a const pointer to int since T
is int*
. 您的示例的问题是
p
是指向const int的指针 ,但Derived<int*>
的构造函数将const指针指向int,因为T
是int*
。 This may seem confusing, but you can think of const
as having a higher precedence than *
in type declarations. 这可能看起来令人困惑,但您可以将
const
视为在类型声明中具有比*
更高的优先级。 So in const int *
the const
applies to int
and then *
applies to the whole thing making p
a pointer to const int whereas for const T
, the const applies to T
, which is actually int*
so const T argD
makes argD
a const pointer to int . 所以在
const int *
中const
适用于int
然后*
适用于整个事情使p
成为指向const int的指针而对于const T
,const适用于T
,实际上是int*
所以const T argD
使argD
成为const指针到int 。
Using this same idea all your Foo
examples can be easily deciphered. 使用同样的想法,您可以轻松破译所有
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
In general only Foo(T a)
and Foo(const T a)
cannot be overloaded because it doesn't matter to the caller whether the argument is copied into a constant variable or not. 通常只有
Foo(T a)
和Foo(const T a)
不能重载,因为调用者是否将参数复制到常量变量中并不重要。
More specifically, if T
is char *
(pointer to char) 更具体地说,如果
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
If T
is const char*
(pointer to a const char) things are much the same 如果
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
If T
is char* const
(const pointer to a char) then all the const T
overloads are redundant because const T
is equivalent to T
when T
is already const. 如果
T
是char* const
(指向char的const指针),则所有const T
重载都是冗余的,因为当T
已经是const时, const T
等于T
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 (+))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.