此代码在 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)到模板参数。因为这将导致返回类型推导以确定两个冲突类型(int
为 0
,T
为 sum
),我们还必须更改第一行以返回 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/