为什么 auto 关键字不能与指向函数的指针的初始化列表一起使用?

Why isn't auto keyword working with initialization list of pointers to functions?

本文关键字:初始化 指针 列表 一起 函数 关键字 auto 不能 为什么      更新时间:2023-10-16

我最近一直在试用C++11,特别是auto关键字,结果证明它非常有趣和有用。

然而,由于某些原因,它不适用于函数指针的初始化列表。首先,我在书中寻找答案,发现"auto关键字只适用于单个初始化值,而不适用于初始化列表",但当我尝试过时:

auto foo = { "bar", "bar", "bar" };
std::cout << *(foo.begin());

它运行得很好,但当我尝试这样做时:

// bar is a simple void bar() function
auto foo = { bar, bar, bar };

Visual Studio编译器吐唾沫:

error C1001: An internal error has occurred in the compiler.

如果有效:

auto foo = bar;

因此,我决定在互联网上进行一次小旅行,以获得更多关于std::initializer_list的信息,在那里我了解到它实际上与std::vector非常相似。那么,我为什么不试试呢?

std::vector<void (*)()> foo = { bar, bar, bar };
(*foo.begin())();

工作完美无瑕。从那以后,我陷入了困境,我不知道为什么auto关键字不能用于函数指针的初始化列表。为什么它会出现问题,特别是在指向函数的指针方面,C++标准对它最重要的说明是什么?

编辑

我也尝试过使用GCC和yup做同样的事情,它很有效,所以看起来你们是对的,MSVC编译器有一个错误。我想我需要等到他们修复它,同时我会简单地使用GCC。

这似乎只是MS VC++的一个bug。至少这个代码

auto foo = { bar, bar, bar };

其中bar是一些用GCC成功编译的函数。

消息

error C1001: An internal error has occurred in the compiler.

显示这是编译器中的一个错误。我刚刚在gcc 4.7.2中尝试过,下面的代码运行良好,并打印出"Hello!":

#include <iostream>
void bar()
{
std::cout << "Hello!n";
}
int main()
{
auto foo = { bar, bar, bar };
(*(foo.begin()))(); // prints "Hello!"
}

您的代码应该可以工作,这是一个VC++错误。然而,在表达式中

auto foo = { bar, bar, bar };

foo的元素不是指向函数的指针,而是指向函数的引用。如果您希望foo包含指向函数的指针,则需要将其创建为:

auto foo = { &bar, &bar, &bar };

这个例子证明了这种差异:

#include <type_traits>
void bar() {}
template<typename T>
using remove_ref_and_const = typename std::remove_const<
typename std::remove_reference<T>::type
>::type;
int main()
{
static_assert(std::is_same<
remove_ref_and_const<decltype(bar)>,
void()>::value, "Oops1");
static_assert(std::is_same<
remove_ref_and_const<decltype(&bar)>,
void(*)()>::value, "Oops2");
}

现场演示


编辑:上面的答案并不完全正确。尽管bar&bar之间存在差异,但当您将它们添加到初始值设定项列表中时,前者也会衰减为指向函数的指针。下面的几个static_assert演示了这一点。

auto foo1 = { bar, bar, bar };
auto foo2 = { &bar, &bar, &bar };
static_assert(std::is_same<
remove_ref_and_const<decltype(*foo1.begin())>,
void(*)()>::value, "Oops3");
static_assert(std::is_same<
remove_ref_and_const<decltype(*foo2.begin())>,
void(*)()>::value, "Oops4");

现场演示