使用嵌套模板化变量解决 Visual Studio 内部编译器错误

Posted

技术标签:

【中文标题】使用嵌套模板化变量解决 Visual Studio 内部编译器错误【英文标题】:Working Around a Visual Studio Internal Compiler Error With Nested Templated Variables 【发布时间】:2019-10-16 04:23:06 【问题描述】:

我正在尝试编写代码来索引函数的参数类型:

template <typename R, typename... ARGS>
R function_return(R(*)(ARGS...));

template <typename R, typename... ARGS>
std::tuple<ARGS...> function_parameters(R(*)(ARGS...));

template <int I, typename T>
using get_type = typename std::conditional_t<(I < 0), std::tuple_element<static_cast<int>(std::tuple_size_v<T>) + I, T>, std::tuple_element<I, T>>::type;

template <int I, typename T>
using parameter_type = get_type<I, decltype(function_parameters(std::declval<T>()))>;

Live Example (ICE under VS) Live Example (working on GCC)

但是当我尝试在 visual-studio-2017 上使用它时,我得到一个内部编译器错误:

致命错误 C1001:编译器发生内部错误。

还有其他方法可以解决内部编译器错误吗?

【问题讨论】:

已经提交了错误单?也就是说,您的代码中有一件事是我要避免的:将ALL_UPPERCASE 用于常规标识符。如果任何 win32 标头以某种方式泄漏到该代码中,您会得到一堆带有它的宏,其中一些是完全邪恶的。 @UlrichEckhardt 现场示例给出了输出,而 obvs 没有 ICE。该错误在 VS 中而不在 GCC 6.3 中 不过,我得说it works for me。 您可以在 godbolt.org 上展示示例或上传到其他一些实际使用 MSVC 的在线编译器站点。 可以升级到VS2019吗? :D 【参考方案1】:

这可能取决于 VS2017 的确切(子)版本,因为我的代码不会产生 ICE。但是,代码仍然存在问题,因为它可能会实例化 std::tuple_element&lt;2147483647, T&gt; 或类似的东西。您需要确保只评估正确的分支。将您对 get_type 的定义替换为:

template <int I, typename T, bool negative = (I < 0)>
struct get_type_impl;

template <int I, typename T>
struct get_type_impl<I, T, true>

  using type = typename std::tuple_element<static_cast<int>(std::tuple_size<T>::value) + I, T>::type;
;

template <int I, typename T>
struct get_type_impl<I, T, false>

  using type = typename std::tuple_element<I, T>::type;
;

template <int I, typename T>
using get_type = typename get_type_impl<I, T>::type;

这适用于我的 VS 2017(cl 版本 19.12)

【讨论】:

可以确认this fixes the problem on the affected version。干得好!【参考方案2】:

就像mentioned here 一样,visual-studio-2017 似乎在与模板化的 using 语句相互传递时遇到困难。 (我在 15.6.7 上看到了内部编译器错误;mentioned here 这可能已通过补丁修复。)

我已经能够通过在单个 using 语句中捕获所有功能来解决它​​:

template <typename R, typename... ARGS>
R function_return(R(*)(ARGS...));

template <typename R, typename... ARGS>
std::tuple<ARGS...> function_parameters(R(*)(ARGS...));

template <int I, typename T, typename X = decltype(function_parameters(std::declval<T>()))>
using parameter_type = typename std::conditional_t<(I < 0), std::tuple_element<static_cast<int>(std::tuple_size_v<X>) + I, X>, std::tuple_element<I, X>>::type;

【讨论】:

以上是关于使用嵌套模板化变量解决 Visual Studio 内部编译器错误的主要内容,如果未能解决你的问题,请参考以下文章

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

在 Visual Studio 2015 解决方案中实现 C++ 模板的正确方法是啥?

Visual Studio 解决方案模板 - 链接源代码管理项目

Visual Studio 2017 的多个 Git 存储库

使用Visual Studio扩展插件Visual assist X给代码插入注释模板

使用Visual Studio扩展插件Visual assist X给代码插入注释模板