解决 GCC 错误,创建立即访问的函数指针自动类型向量文字

问题描述 投票:0回答:1

问题

GCC 中的已知错误 <12 precludes initialising and immediately accessing implicitly typed vectors like so:

auto elem = (std::vector {1, 2, 3})[0];
对于某些类型,可以使用 

decltype

:
来解决

auto elem = (std::vector <decltype(1)> {1, 2, 3})[0];
可惜这个解决方法不适用于函数指针:

void f() { } // won't compile in Clang nor GCC for unknown (by me) reason auto elem = (std::vector <decltype(f)> {f,f,f})[0]; // won't compile in GCC due to known bug auto elem = (std::vector {f, f, f})[0];
为什么此解决方法不适用于函数指针,尽管它适用于其他类型?是否有另一种解决方法,可以初始化并立即访问函数指针向量,而无需显式声明指针类型(即函数签名)?

更多背景

考虑创建元素向量而不显式声明元素类型:

auto vec = std::vector{1, 2, 3};

这可以与
Clang

GCC(使用 -std=c++17)很好地编译。然而,我希望避免将向量分配给变量,而是在同一行中获取元素:

auto elem = (std::vector{1, 2, 3}) [0];

这在
Clang
中编译得很好,但在

GCC失败,有异常 error: missing template arguments after ‘vector<...auto...>’ | auto elem = (std::vector{1, 2, 3})[0]; | ^~~~~~ In file included from /usr/include/c++/11/vector:67, /usr/include/c++/11/bits/stl_vector.h:389:11: note: ‘template<class _Tp, class _Alloc> class std::vector’ declared here | class vector : protected _Vector_base<_Tp, _Alloc> | ^~~~~~

这与在
C++17
之前的标准中编译我的原始示例时触发的错误相同。就好像 GCC 无法识别隐式类型语法(如果它是子表达式)。这是 GCC 中的错误吗?

无论如何,我可以使用
decltype

来补救:

auto elem = (std::vector <decltype(0)> {1, 2, 3}) [0];

它可以在
Clang

GCC 中编译。 唉,我实际上并不希望存储整数

,而是存储

函数指针!下面的代码在 Clang 中编译良好,但在 GCC 中编译失败,正如我们所看到的整数情况。 void f() {} auto elem = (std::vector {f, f, f}) [0]; 唉,尝试使用适用于整数的decltype

不适用于函数指针!表达

(std::vector <decltype(f)> {f, f, f}) [0]

将无法在 Clang 

 
GNU

中编译,并出现错误: In file included from /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/iostream:43: In file included from /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/ios:222: In file included from /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__locale:15: In file included from /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__memory/shared_ptr.h:23: /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__memory/allocator.h:151:19: error: multiple overloads of 'address' instantiate to the same signature 'const_pointer (const_reference) const noexcept' (aka 'void (*(void (&)()) const noexcept)()') const_pointer address(const_reference __x) const _NOEXCEPT { ^ /usr/include/c++/11/ext/new_allocator.h: In instantiation of ‘class __gnu_cxx::new_allocator<void()>’: /usr/include/c++/11/bits/allocator.h:124:11: required from ‘class std::allocator<void()>’ /usr/include/c++/11/bits/stl_vector.h:87:21: required from ‘struct std::_Vector_base<void(), std::allocator<void()> >’ /usr/include/c++/11/bits/stl_vector.h:389:11: required from ‘class std::vector<void()>’ test.cpp:25:48: required from here /usr/include/c++/11/ext/new_allocator.h:96:7: error: ‘const _Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::const_reference) const [with _Tp = void(); __gnu_cxx::new_allocator<_Tp>::const_pointer = void (*)(); __gnu_cxx::new_allocator<_Tp>::const_reference = void (&)()]’ cannot be overloaded with ‘_Tp* __gnu_cxx::new_allocator<_Tp>::address(__gnu_cxx::new_allocator<_Tp>::reference) const [with _Tp = void(); __gnu_cxx::new_allocator<_Tp>::pointer = void (*)(); __gnu_cxx::new_allocator<_Tp>::reference = void (&)()]’ 96 | address(const_reference __x) const _GLIBCXX_NOEXCEPT | ^~~~~~~ 如何在不显式指定类型的情况下初始化和访问这个内联临时向量,这当然会编码函数签名和返回类型?

我为什么要这么做?
我有多个具有不同签名和返回类型的单整数模板函数:

template <int N> void f(int x) { ... } template <int N> float g(int x, int y) { ... } ...

模板参数通知函数中的编译时优化(有关更多信息,请参阅

this SO post

)。选择被调用函数的模板参数的一个简单方法是使用所有合法模板参数构建指向该函数的指针数组:

std::vector <void(*)(void)> f_funcs { f<0>, f<1>, f<2>, ... };

int param = 2;
f_funcs[param]();

注意,我明确指定了类型 void(*)(void)

f
 的签名)作为向量模板。我必须为每个类型明确的函数对数组初始化进行硬编码:

std::vector <float(*)(int,int)> g_funcs { g<0>, g<1>, g<2>, ... }; int param = 2; float ret = g_funcs[param](6,9);

这编译得很好,但是是乏味的样板文件。我希望避免对每个函数的函数指针数组文字进行硬编码,特别是因为其中一些函数接受 
two
模板参数并需要 2D 初始化程序。所以,我写了一个宏:

#define GET_FUNC(func, param) \
    (vector {func<0>, func<1>, func<2>, ...} ) [param]

int param = 3;
auto f_ = GET_FUNC(f, param);
auto g_ = GET_FUNC(g, param);

f_();
float x = g_(6,9);

使用隐式类型可以避免我将 f

g
 的签名传递给宏。这在 
Clang

中编译得很好,但如上所述,

not
GCC
中编译。 介绍decltype... #define GET_FUNC(func, param) \ (vector <decltype(func<0>)> {func<0>, func<1>, func<2>, ...}) [param]

无法在

Clang

nor
 
GCC

中编译。 正如 Jarod42 所评论的,支持早于 12 的 GCC 版本的解决方法是维护一个显式指针数组:

c++ vector c++17 function-pointers stdvector
1个回答
0
投票

尽管有评论,这不是这个

相关但更简单的问题
中提出的(不适用的)解决方案。这个问题
不是

重复(天哪)! user12002570提出的解决方案 对于我的问题中描述的模板化函数不起作用

godbolt)。 // fails to compile in GCC < v12 auto func = ((vector {f<0>, f<1>, f<2>}))[0];

© www.soinside.com 2019 - 2024. All rights reserved.