Visual Studio 中的模板化函数指针数组

Templated Function Pointer Arrays in Visual Studio

本文关键字:函数 指针 数组 Studio Visual      更新时间:2023-10-16

Guillaume Racicot 对这个问题给出了一个很好的答案,即我如何专门化模板变量。但是我在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;
    }
}

在 gcc 输出中:


1 阿拉伯数字
3

但在 visual-studio-2017 中,只有输出:


1 阿拉伯数字

我可以做些什么来解决这个问题吗?

欢迎来到编译器错误的世界!您的语法是完全有效的,但只有 GCC 可以编译它。

到目前为止,我测试了多个clang,gcc和msvc版本。

函数指针原始数组的变体,只有 GCC 才能正确解析它。Clang 8.0.0 将崩溃,MSCV 不会编译它。

我尝试了另外两种变体:使用模板别名和std::array

函数指针别名模板:

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编译时间成本很小,但到目前为止,原始数组的可移植性令人惊讶地低。