Visual Studio 中的模板化函数指针数组
Templated Function Pointer Arrays in Visual Studio
Guillaume Racicot gave an excellent answer to on how I could specialize template variables. But I'm having trouble in 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;
}
}
1
2
3
但是在visual-studio-2017中只输出:
1
2
有什么办法可以解决这个问题吗?
欢迎来到编译器错误的世界!您的语法完全有效,但只有 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>
};
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
编译时间成本很小,但原始数组目前的可移植性出奇地差。
Guillaume Racicot gave an excellent answer to
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;
}
}
1
2
3
但是在visual-studio-2017中只输出:
1
2
有什么办法可以解决这个问题吗?
欢迎来到编译器错误的世界!您的语法完全有效,但只有 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>
};
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
编译时间成本很小,但原始数组目前的可移植性出奇地差。