C++
我想知道一个指针是否可以被隐式或显式地转换为 T const * const
,即使它不是已经是一个两个const
指针(例如T const * const
)。在被用于初始化声明为 T const * const
的变量之前或之后,该指针是否可以通过某些方式(例如函数)进行处理或转换。我该怎么做?
我认为如果我从一个 T*
开始,那么一次 const_cast
(或两次,在情况下只能每次转换一个 const
)就足够了,但显然并不是这样的。代码中的许多变量都显示了不同的失败尝试,试图通过转换或从函数返回来产生一个带有尾随 const
的 T const * const
。每次转换都无法返回一个带有尾随 const
的指针。(我将 *
左边的 const
称为前导 const
,右边的称为尾随 const
。)由于转换失败,我尝试通过直接初始化强制使用 const
。这是在 VC11
中编译的。在 stack-crooked.com 上的 g++ 给出了逻辑上等效的控制台输出,尽管对于 typeid(/*...*/).name()
使用了不同的名称。
#include <iostream>
#include <typeinfo>
using namespace std;
int const * const foo()
{
return nullptr;
}
int main()
{
int x = 7;
auto a1 = &x;
cout << typeid(a1).name() << endl;
auto a2 = const_cast<int const *>(&x);
cout << typeid(a2).name() << endl;
auto a3 = const_cast<int * const>(&x);
cout << typeid(a3).name() << endl;
auto a4 = const_cast<int const * const>(&x);
cout << typeid(a4).name() << endl;
auto a5 = const_cast<int const * const>(a4);
cout << typeid(a5).name() << endl;
auto a6 = (int const * const) &x;
cout << typeid(a6).name() << endl;
auto a7 = static_cast<int const * const>(a4);
cout << typeid(a7).name() << endl;
auto a8 = reinterpret_cast<int const * const>(a4);
cout << typeid(a8).name() << endl;
auto a9 = foo();
cout << typeid(a9).name() << endl;
int const * const a10 = &x;
cout << typeid(a10).name() << endl;
cout << ( typeid(a10) == typeid(a4) ) << endl;
auto a12 = a10;
cout << typeid(a12).name() << endl;
cout << ( typeid(a12) == typeid(a4) ) << endl;
}
预期结果与实际结果,以及问题:
问题编号对应相同编号的a#
变量。
- 得到了预期结果
int *
- 得到了预期结果
int const *
- 期望的是
int* const
,但得到的是int*
。为什么const_cast
忽略了其尾随的const
参数?由于返回值与参数具有相同的常量性和类型,那么转换是否运行? - 期望的是
int const * const
,但得到的是int const*
。为什么const_cast
忽略了其尾随的const
参数? - 我想看看
const_cast<int const * const>
是否会在结果中包含尾随的const
,因为参数a4
已经具有前导的const
。期望的是int const * const
。得到了int const*
。为什么const_cast
忽略了其尾随的const
参数? - 期望的是
int const * const
。得到了int const*
。为什么显式转换仍然排除了尾随的const
? - 期望的是
int const * const
。得到了int const*
。为什么static_cast
排除了尾随的const
? - 期望的是
int const * const
。得到了int const*
。为什么reinterpret_cast
排除了尾随的const
? - 期望从函数返回的
int const * const
的初始化结果仍然排除结果中的尾随const
。得到了int const*
。 - 从控制台输出中得到了
int const*
,但从调试器中没有得到int const * const
。变量a10
明确声明为int const * const
,那么为什么typeid().name()
排除了尾随的 const?operator==
得到了1
,那么为什么对于a10
,typeid()
本身(不仅仅是名称)等价于a4
的类型标识符?VC11 调试器将a10
的类型列为int const * const
。为什么与typeid()
和typeid().name()
的结果不同?哪一个是正确的? - 变量名
a11
被省略,因为它看起来像单词 “all”。 - 我期望
a12
是int const * const
,因为它被初始化为a10
,后者明确声明为int const * const
。operator==
得到了1
,那么typeid()
仍然是int const*
。从控制台输出和调试器中都得到了int const*
。为什么它们与预期结果不同?
const
不是顶层const
修饰符;只有尾随的const
是吗?由于auto
会忽略顶层的const
修饰符,所以我如何在失去顶层const
修饰符之前观察或者最好是保存每次转换的结果?const_cast<T const * const>(&t_type)
可以将T*
直接强制转换为T const * const
,还是我需要两个强制转换,每个const
都需要一个? - CodeBrickstypeid
运算符的操作数的类型标识。 - Igor Tandetnikconst
修饰符,无论它在开始还是结尾词法上出现。在const int n = 42
和int const n = 42
中,const
修饰符都是顶层的。在const int* const! p
、int const * const! p
、typedef const int* CP; const! CP p
中,我用感叹号标记了顶层限定符。 - Igor Tandetnikconst_cast
返回值。只要我找到了,就不需要观察顶层const修饰符。从您的回答中:“const_cast确实按您所想的方式工作。” 我想更多地澄清,因为我不知道它确切返回什么; OP问是否可以在顶层const中进行强制转换以及需要多少次强制转换才能将顶层和非顶层const都进行转换。尽管OP没有说要从左值转换指针,但这就是我的意思。并非OP中的每个转换都来自右值(例如a4
)。尝试从标准中找到答案,但有些部分存在疑问。 - CodeBricks