繁体   English   中英

为什么C ++允许但忽略const对函数类型的应用?

[英]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;
}

由于&FooFunc*类型的右值,我认为我应该能够将它放在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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM