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]
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) { ... }
...
)。选择被调用函数的模板参数的一个简单方法是使用所有合法模板参数构建指向该函数的指针数组:
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]
无法在
Clangnor
GCC
中编译。 正如 Jarod42 所评论的,支持早于 12 的 GCC 版本的解决方法是维护一个显式指针数组:
尽管有评论,这不是这个
相关但更简单的问题中提出的(不适用的)解决方案。这个问题不是
重复(天哪)! user12002570提出的解决方案 对于我的问题中描述的模板化函数不起作用
(godbolt)。
// fails to compile in GCC < v12
auto func = ((vector {f<0>, f<1>, f<2>}))[0];