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&lt;auto(*)(const vec&amp;) -&gt; double, 3&gt;

结果如下:

+------------+-------+-------+-------+
| 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 存在于缩小的动态数组中

C++ 项目在 Visual Studio 2019 中触发了断点

在 Visual Studio C++ 6.0 中使用模板函数