![](/img/trans.png)
[英]Why C doesn't allow implicit conversion from char ** to const char *const * (and C++ does)?
[英]Why does C++ allow but ignore the application of const to function types?
我真正开始探索C ++的不寻常角落。 从这个问题中了解了函数的真实类型而不是函数指针,我尝试了解函数类型,并提出了这个奇怪的案例:
typedef int Func(int);
int Foo(int x) { return 1; }
int main()
{
const Func*& f = &Foo;
return 0;
}
由于&Foo
是Func*
类型的右值,我认为我应该能够将它放在const引用中,但是我从g ++ 4.6中得到了这个错误:
funcTypes.cpp: In function ‘int main()’:
funcTypes.cpp:7:23: error: invalid initialization of non-const reference of type ‘int (*&)(int)’ from an rvalue of type ‘int (*)(int)’
但是f
是常量! 对我来说很明显,简单地忽略了const对函数(或对指针等的引用/引用)的应用; 这段代码编译得很好:
template <typename A, typename B>
struct SameType;
template <typename A>
struct SameType<A, A> { };
typedef int Func(int);
int main()
{
SameType<const Func, Func>();
return 0;
}
我猜这是促进拉出他们的is_function
类型特征,但我的问题是 - 为什么C ++通过忽略它而不是禁止它来允许它?
编辑:我现在意识到,在第一个例子中, f
是非const,而const FuncPtr& f = &Foo
确实有效。 然而,这只是背景,真正的问题是上面的问题。
但是f是常量!
不,这不对。 你很困惑
const Func*& f = &Foo;
同
Func* const& f = &Foo;
前者是const指针的非常量引用。 后者是一个非const指针的const引用。
这就是为什么我总是在* /&之前而不是在类型之前写出const-ness。 我总是把第一个案例写成
Func const*& f = &Foo;
然后从右到左阅读:引用指向const Func的指针。
在c ++ 03中,它没有被忽略,但是形象不对(并且是一个sfinae案例)。 我猜他们在c ++ 11中改变了它,因为那时你可以简单地将函数参数设置为const F&
并且可以将rvalue函数对象和普通函数传递给它。
请参阅此更改的DR http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#295
&Foo
是一个指针。 一般来说,我建议避免引用指针( const
或no)。 至少,除非你知道你在做什么。
所以你应该:
const Func *f = &Foo;
或者真的,你可以完全const
:
Func *f = &Foo;
为什么C ++通过忽略它而不是禁止它来允许这个?
因为你在谈论两件不同的事情。
在C ++中,函数类型和函数指针之间存在差异。 Foo
是一个函数类型,特别是int(int)
。 &Foo
是一个int(*)(int)
类型的函数指针。 在必要时,函数类型会降级为函数指针(很像数组类型会降级为指针)。 但它们是截然不同的(就像数组一样)。
所以你的两个案例不一样。 你的第一种情况是处理一个函数指针,你的第二种情况是处理一个函数类型(这是模板参数被推导出来的)。
至于为什么函数类型吞下const
,那是因为函数类型的值已经隐式地保持不变。 你无法改变它们。 您可以对函数类型执行的唯一操作是()
(或转换为函数指针)。 因此,如果T
是函数类型,则const T
等效于T
Visual Studio 2010实际上会发出警告。
以下编译正常:
typedef int Func(int);
int Foo(int x) { return 1; }
int main()
{
Func* const& f = &Foo; //ok
return 0;
}
请注意,const语句与从右到左的指针和引用一起进行计算。 你写的最左边的最后一个const转换为一个Name的最后一个可能的位置( 关于const放置的C ++ FAQ )。 于是
const Func*& f
是由编译器翻译而来的
Func const*& f
因此,您获得了一个不是您想要的常量指针的引用。 此外,如果您不必使用,我不会使用对函数指针的引用。
不, f
不是常数。 首先,它是对一些可变类型的引用(可变类型碰巧是一个const指针,即一个可变指针,指向你保证不会通过该特定指针改变的东西)。 但是,使用&Foo
创建临时(类型为Func*
)并且您不能将临时值分配给可变引用。 您只能将其分配给const引用。 这正是错误信息告诉你的。
有时错误消息可能有点神秘。
我在ideone上放了一个例子来说明gcc为各种各样的东西打印的类型:
#include <iostream>
typedef int(Func)(int);
typedef Func* FuncPtr;
typedef FuncPtr& FuncPtrRef;
typedef FuncPtr const& FuncPtrConstRef;
template <typename T> void DisplayType() { T::foo(); }
int main() {
DisplayType<Func>();
DisplayType<FuncPtr>();
DisplayType<FuncPtrRef>();
DisplayType<FuncPtrConstRef>();
}
编译错误给出:
Func
的类型为int ()(int)
(不是有效类型,现在应该在gcc中修复) FuncPtr
的类型为int (*)(int)
FuncPtrRef
的类型为int (*&)(int)
FuncPtrConstRef
的类型为int (* const&)(int)
在您的错误消息中,您有int (*&)(int)
,它是对函数类型的非const指针的引用。
不允许将rvalue绑定到非const引用。
注意:这与被吞噬的const
无关,因为正确诊断了smpark
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.