作为一个练习,我想为容器创建一个通用的模板化求和函数。虽然使用“嵌套模板”重载可以很好地实现我的目标,但我想编写一个仅基于std::begin()
/ std::end()
的函数,以允许它处理那些为这些函数带来重载的内容。并利用C ++ 11 SFINAE的全部功能。
然而,我遇到了返回类型的问题。这是我尝试过的,用数字容器的通用“sum”函数说明:
首先,使用代码:
int arr[] = {1,2,3,4};
vector<int> vec(begin(arr),end(arr));
auto sum1 = sum(vec);
auto sum2 = sum(arr);
这是我对函数的期望 - 从容器和数组开始工作。
这是我尝试解决问题的方法:
template<typename T> auto sum(const T& container) -> decltype(*begin(container)) {
typedef remove_const<remove_reference<decltype(*begin(container))>::type>::type val_type;
val_type sum;
if (is_arithmetic<val_type>::value)
sum = 0;
for (const auto& value: container)
sum = sum + value;
return sum;
}
这有什么问题:它有效,但会发出警告(C4172: returning address of local variable or temporary
)。这显然是一件坏事,基本上会产生未定义的行为。
我尝试通过以下方式定义尾随返回类型:
1. var_type的复制声明
template<typename T> auto sum(const T& container) ->
remove_const<remove_reference<decltype(*begin(container))>::type>::type
这会产生错误:C2923: 'std::remove_const' : 'std::remove_reference<_Ty>::type' is not a valid template type argument for parameter '_Ty'
(很奇怪,因为同样适用于val_type
2.使用容器[0]
template<typename T> auto sum(const T& container) -> decltype(container[0])
这样做有效,但它对container
类型产生了额外的限制,我想避免这种限制,并为C4172
提供vector
3.尝试仅删除参考
template<typename T> auto sum(const T& container) -> remove_reference<decltype(*begin(container))>::type
结果:error C2061: syntax error : identifier 'type'
。
有什么想法吗?
答案 0 :(得分:2)
这很简单:decltype(*std::begin(container))
已解决T const &
。
应用与val_type
相同的操作,添加一些typename
个关键字,这样就可以了。
为什么typename是强制性的?看看错误:
error: expected a type, got ‘std::remove_reference<decltype (* std::begin(container))>::type’
如果您尝试在此表达之前添加typename,您现在拥有:
error: need ‘typename’ before
‘std::remove_const<typename std::remove_reference<decltype (* std::begin(container))>::type>::type’
because
‘std::remove_const<typename std::remove_reference<decltype (* std::begin(container))>::type>’
is a dependent scope
GCC 4.7.2的工作示例:
#include <iostream>
#include <type_traits>
#include <vector>
using namespace std;
template <class T>
auto sum (T const & container)
-> typename remove_const<typename remove_reference<decltype(*begin(container))>::type>::type
{
typedef typename remove_const<typename remove_reference<decltype(*begin(container))>::type>::type val_type;
val_type sum;
if (is_arithmetic<val_type>::value)
sum = 0;
for (const auto& value: container)
sum = sum + value;
return sum;
}
int main ()
{
vector<int> v { 0, 1, 2, 3 };
cout << sum(v) << endl;
}