Visual Studio 中的模板化函数指针数组
Posted
技术标签:
【中文标题】Visual Studio 中的模板化函数指针数组【英文标题】:Templated Function Pointer Arrays in Visual Studio 【发布时间】:2019-11-01 02:52:41 【问题描述】:Guillaume Racicot 对this question 给出了关于如何专门化模板变量的出色回答。但是我在visual-studio-2017 创建函数指针的模板数组时遇到了麻烦。例如这段代码:
struct vec
double x;
double y;
double z;
;
namespace details
template <typename T>
constexpr double X(const T& param) return param.x;
template <typename T>
constexpr double Y(const T& param) return param.y;
template <typename T>
constexpr double Z(const T& param) return param.z;
template <typename T, typename = void>
constexpr double (*my_temp[])(const vec&) = &details::X<T>, &details::Y<T> ;
template <typename T>
constexpr double (*my_temp<T, enable_if_t<is_floating_point_v<decltype(details::X(T()))>>>[])(const vec&) = &details::X<T>, &details::Y<T>, &details::Z<T> ;
int main()
vec foo = 1.0, 2.0, 3.0 ;
for(const auto i : my_temp<decltype(foo)>)
cout << (*i)(foo) << endl;
In gcc outputs:
1 2 3
但在visual-studio-2017 中只输出:
1 2
我可以做些什么来解决这个问题吗?
【问题讨论】:
嗯...此代码似乎是 ICE clang 8,但不是中继。 我无法在 Visual Studio 2017 中使用/std:c++17
编译它,您的意思是不是 Visual Studio 2019?
FWIW,VS2019 无法编译代码,因此您甚至无法升级修复它。
使用std::array
,它适用于所有三个编译器:godbolt.org/z/Ro-WHZ
@JonathanMee 我是说 MSVS 无法处理语法,并不是说它不好。它处理了您之前 Q 中的琐碎案例,但对此很感兴趣。
【参考方案1】:
欢迎来到编译器错误的世界!您的语法完全有效,但只有 GCC 可以编译它。
到目前为止,我测试了多个 clang、gcc 和 msvc 版本。
您使用函数指针原始数组的变体,只有 GCC 可以正确解析它。 Clang 8.0.0 会崩溃,MSCV 不会编译。
我尝试了另外两种变体:使用模板别名和std::array
Function pointer alias template:
template<typename T>
using fptr = auto(*)(T const&) -> double;
template <typename T, typename = void>
constexpr fptr<T> my_temp[] =
&details::X<T>, &details::Y<T>
;
template <typename T>
constexpr fptr<T> my_temp<T, enable_if_t<is_floating_point_v<decltype(details::X(T()))>>>[] =
&details::X<T>, &details::Y<T>, &details::Z<T>
;
std::array
+ CTAD:
template <typename T, typename = void>
constexpr std::array my_temp =
&details::X<T>, &details::Y<T>
;
template <typename T>
constexpr std::array my_temp<T, enable_if_t<is_floating_point<decltype(details::X(T()))>::value>> =
&details::X<T>, &details::Y<T>, &details::Z<T>
;
要删除 CTAD,只需使用 std::array<auto(*)(const vec&) -> double, 3>
。
结果如下:
+------------+-------+-------+-------+
| Compiling? | GCC | Clang | MSVC |
+------------+-------+-------+-------+
| raw array | Yes | ICE | No |
+------------+-------+-------+-------+
| fptr alias | Yes | ICE | Yes |
+------------+-------+-------+-------+
| std::array | Yes | Yes | Yes |
+------------+-------+-------+-------+
请注意,在即将发布的 clang 9 中,它将与 GCC 相提并论。所有版本至少需要 MSVC 2017。通过解决方法,我确信它也可以与 msvc 2015 一起使用。
最后,只要它在您现在需要的平台上运行,就可以了。 std::array
的编译时间成本很小,但到目前为止,原始数组的可移植性令人惊讶。
【讨论】:
clang 8 appears to work 没有?哈哈,我不知道该相信哪个。 我现在也不是。我现在使用的电脑上没有安装clang,只有AppleClang。 @AndyG 和 Guillaume Racicot 好了,伙计们,我知道我们在这里做什么,我可以使用变通方法,但我不明白为什么专门的论点必须始终是void
为此工作。你们能帮我澄清一下吗:***.com/q/56667847/2642059
@JonathanMee:Max 的回答很到位。如果您选择不提供void
,您也许可以编写另一层间接性以上是关于Visual Studio 中的模板化函数指针数组的主要内容,如果未能解决你的问题,请参考以下文章
在Visual Studio中使用Lambdas进行模板化变量错误?
动态创建指针数组时,Visual Studio 不显示完整数组
Visual Studio 调试中将结构体指针转换为结构体数组查看
Visual Studio 警告 C6308 存在于缩小的动态数组中