我编写了这段代码,如果我取消注释第二行,我会收到错误 - “模板参数推断/替换失败:”。是因为C ++中泛型函数的一些限制吗?此外,我的程序不会打印数组b
的浮动答案。有什么我可以做的吗? (抱歉在单个帖子中提出2个问题。)
P.S:我刚开始学习C ++。
#include <iostream>
using namespace std;
template <class T>
T sumArray( T arr[], int size, T s =0)
{
int i;
for(i=0;i<size;i++)
{ s += arr[i];
}
return s;
}
int main()
{
int a[] = {1,2,3};
double b[] = {1.0,2.0,3.0};
cout << sumArray(a,3) << endl;
cout << sumArray(b,3) << endl;
cout << sumArray(a,3,10) << endl;
//cout << sumArray(b,3,40) << endl; //uncommenting this line gives error
return 0;
}
左编辑1:将40更改为40.0后,代码可以正常工作。这是我得到的输出:
6
6
16
46
我在第二种情况下仍然没有得到浮动答案。有什么建议吗?
答案 0 :(得分:19)
原因是编译器无法推断出Memory Address Values
1000 0x39
1001 0x05
1002 0x00
1003 0x00
的类型。
它应该如何理解你最后一个例子的T
是什么?第一个参数(T
)的类型是b
,而在函数定义中它是double[]
。因此,T[]
看起来应该是T
。但是,第三个参数(double
)的类型为40
,因此看起来int
应为T
。因此错误。
将int
更改为40
会使其有效。另一种方法是在模板声明中使用两种不同的类型:
40.0
请注意,我必须明确地将#include <iostream>
using namespace std;
template <class T, class S = T>
T sumArray( T arr[], int size, S s =0)
{
int i;
T res = s;
for(i=0;i<size;i++)
{ res += arr[i];
}
return res;
}
int main()
{
int a[] = {1,2,3};
double b[] = {1.0,2.0,3.1};
cout << sumArray(a,3) << endl;
cout << sumArray(b,3) << endl;
cout << sumArray(a,3,10) << endl;
cout << sumArray(b,3,40) << endl; //uncommenting this line gives error
return 0;
}
投射到s
,否则最后一个示例将丢失小数部分。
但是,此解决方案仍不适用于T
,因为它会将sumArray(a,3,10.1)
转换为10.1
,因此如果这也是一个可能的用例,则需要更准确的处理。使用c ++ 11功能的完整工作示例可能类似于
int
此模板功能的另一个可能的改进是自动推断数组大小,请参阅TartanLlama的答案。
答案 1 :(得分:4)
sumArray(b,3,40)
40
的类型为int
,但b
的类型为double[3]
。当您将这些作为参数传递时,编译器将获得T
的冲突类型。
解决此问题的一种简单方法是传入double
:
sumArray(b,3,40.0)
但是,您可能最好通过添加另一个模板参数来允许在呼叫站点进行转换。您还可以添加一个来为您推断出数组的大小,这样您就不需要明确地传递它:
template <class T, class U=T, std::size_t size>
U sumArray(T (&arr) [size], U s = 0)
U
参数默认为T
,以支持s
的默认值。请注意,为了推断出数组的大小,我们需要传递对它的引用而不是传递值,这会导致它衰减为指针。
现在调用如下:
sumArray(b,40)
答案 2 :(得分:3)
在
template <class T>
T sumArray( T arr[], int size, T s =0)
^ ^
两者(可推导)T
应匹配。
在sumArray(b, 3, 40)
中,第一个为double
,第二个为int
。
解决问题有几种可能性
,请致电sumArray(b, 3, 40.0)
或sumArray<double>(b, 3, 40);
使用额外参数:
template <typename T, typename S>
auto sumArray(T arr[], int size, S s = 0)
根据您的需要,返回类型可以是T
,S
或decltype(arr[0] + s)
。
使参数不可导出:
template <typename T> struct identity { using type = T;};
// or template<typename T> using identity = std::enable_if<true, T>;
template <typename T>
T sumArray(T arr[], int size, typename identity<T>::type s = 0)
答案 3 :(得分:2)
应该是
sumArray(b,3,40.0)
因此,T
将推断为double
。在您的代码中,它是int
。
答案 4 :(得分:1)
扣除失败时的另一个选择是明确告诉编译器你的意思:
cout << sumArray<double>(b,3,40) << endl;
答案 5 :(得分:0)
编译器不知道T
应该是int
还是double
。
您可能希望执行以下操作,以保持传递类型的最高精度:
template <class T, class S>
std::common_type_t <T, S> sumArray (T arr [], std::size_t size, S s = 0)
{
std::common_type_t <T, S> sum = s;
for (std::size_t i = 0; i != size; ++i)
{
sum += arr[i];
}
return sum;
}
但是,您正在编写的功能已经存在。这是std::accumulate
:
std::cout << std::accumulate (std::begin (b), std::end (b), 0.0) << std::endl;
答案 6 :(得分:-1)
模板只接受一种类型的数据,例如,如果发送一个double数组,那么运行时将推断:
Template = double []
所以每次他都会看到它,他会期待一系列的双打。 sumArray(b,3,40)
传递“b”(这是一个双精度数组)但是你传递“40”,运行时不能隐式转换为double。
所以代码
sumArray(b,3,40.0)
将起作用