C++:为什么这个 constexpr 模板函数会在 VS2017 中导致内部错误?(在 gcc 中是可以的)

标签 c++ visual-studio templates gcc constexpr

此代码在 GCC 中编译良好,但在 Visual Studio 2017 编译器中导致内部错误。我的代码有什么问题?或者这是一个编译器问题?我听说 VS 不使用两阶段名称查找,这在某些情况下会导致问题。

template <typename T>
constexpr auto doSomeSum(const T* a, const T* b) {
    if (a > b)return 0;
    auto sum = 0;
    while (a != b)
        sum += *(a++);
    return sum;
}

int main()
{
    constexpr int arr[] = { 1,2,3,4,5,6,7,0b1000,9,10 };
    constexpr float second[] = { 1,2,3,4,5,6,7,8,9,10 };
    constexpr auto a = doSomeSum<int>(arr, arr+10);
    constexpr auto b = doSomeSum<float>(second,second+10); //works if I comment this line
    return 0;
}

最佳答案

问题(也出现在 MSVC 2015 中)似乎是它将返回类型和 sum 的类型都推断为 int,然后每当T 是不同的类型。我不确定 2017 年,但 2015 年会在崩溃之前发出此警告:

main.cpp(6): warning C4244: '+=': conversion from 'const float' to 'int', possible loss of data
main.cpp(15): note: see reference to function template instantiation 'int doSomeSum(const T *,const T *)' being compiled with

    [
        T=float
    ]

第 6 行是:

    sum += *(a++);

因此,它将*(a++) 视为const float,但将sum 视为int;这是因为 sum 是用整数文字 0 初始化的。然而,我们可以轻松解决此问题,方法是使用 T{0} 对其进行初始化,将 sum 的类型绑定(bind)到模板参数。因为这将导致返回类型推导以确定两个冲突类型(int0Tsum),我们还必须更改第一行以返回 T{0}。因此,最终结果是:

template <typename T>
constexpr auto doSomeSum(const T* a, const T* b) {
    if (a > b)return T{0};
    auto sum = T{0};
    while (a != b)
        sum += *(a++);
    return sum;
}

使用 Compiler Explorer 测试和 RiSE4Fun's MSVC 2015 online environment (请注意,后者不提供任何链接到单个 session 的工具)。使用 GCC and Clang 测试原始代码证明两者都有相同的问题,Clang 也因此发出错误。

关于C++:为什么这个 constexpr 模板函数会在 VS2017 中导致内部错误?(在 gcc 中是可以的),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43079040/

相关文章:

visual-studio - 制作 | UWP::使用 Cmake 构建通用 Windows 应用程序

c++ - c/c++ for windows 中的 DNS 服务器

javascript - 下划线方法 _.template() 不编译我的模板

c++ - boost 库更新后模板函数调用不起作用

c++ - STL 容器库 - 在分配器类的不同实例上调用分配/解除分配是否合法?

c++ - 错误 C4430、C2146 - 缺少类型说明符 - 假定为 int。注: C++ does not support default-int

c++ - 如何通过函数传递数组并将其返回

c++ - g++ 错误 : expected primary-expression

c++ - 需要更多关于为 '_MSC_VER' 检测到的 LNK2038 不匹配的解释

c++ - 不完整类型的调用运算符的 decltype 的特殊行为