使用嵌套模板化变量解决 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<2147483647, T>
或类似的东西。您需要确保只评估正确的分支。将您对 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 2015 解决方案中实现 C++ 模板的正确方法是啥?
Visual Studio 解决方案模板 - 链接源代码管理项目
Visual Studio 2017 的多个 Git 存储库