【发布时间】:2021-09-03 11:12:31
【问题描述】:
我正在尝试自学 SFINAE 模式,对于我正在写的东西,我想编写一个函数,该函数接受 start、end 迭代器到算术类型的值(例如,用于求和)。这是我想出的:
我的main.cpp:
#include <iostream>
#include <vector>
#include "summer.hpp"
int main()
{
std::vector<double> vec {0.1, 0.2, 0.3}; // these are OK
auto sum = summer(vec.begin(), vec.end());
std::cout << sum << std::endl;
std::vector<std::string> vec2 {"a", "b"}; // these should be rejected
auto sum2 = summer(vec2.begin(), vec2.end());
std::cout << sum2 << std::endl;
return 0;
}
然后summer.hpp:
#include <type_traits>
template <
typename Iter,
typename = typename std::enable_if_t<std::is_arithmetic<Iter>::value_type, Iter>,
typename T = typename Iter::value_type
>
T summer(Iter start, Iter end)
{
T sum{};
for (auto it = start; it != end; it++)
{
sum += *it;
}
return sum;
}
上面的 SFINAE 位是我从 this answer 获取的,只是调整它以使用与迭代器指向的类型 (value_type) 相对应的类型特征。但我正在努力编译它,我收到一连串关于 value_type 被解析为非类型但产生类型和提示的抱怨,我应该在它前面加上 typename (这是错误的):
$ g++ --std=c++17 main.cpp && ./a.out
main.cpp: In function ‘int main()’:
main.cpp:10:45: error: no matching function for call to ‘summer(std::vector<double>::iterator, std::vector<double>::iterator)’
10 | auto sum = summer(vec.begin(), vec.end());
| ^
In file included from main.cpp:4:
summer.hpp:8:3: note: candidate: ‘template<class Iter, class, class T> T summer(Iter, Iter)’
8 | T summer(Iter start, Iter end)
| ^~~~~~
summer.hpp:8:3: note: template argument deduction/substitution failed:
summer.hpp:5:5: error: dependent-name ‘std::is_arithmetic<_Tp>::value_type’ is parsed as a non-type, but instantiation yields a type
5 | typename = typename std::enable_if_t<std::is_arithmetic<Iter>::value_type, Iter>,
| ^~~~~~~~
summer.hpp:5:5: note: say ‘typename std::is_arithmetic<_Tp>::value_type’ if a type is meant
main.cpp:13:48: error: no matching function for call to ‘summer(std::vector<std::__cxx11::basic_string<char> >::iterator, std::vector<std::__cxx11::basic_string<char> >::iterator)’
13 | auto sum2 = summer(vec2.begin(), vec2.end());
| ^
In file included from main.cpp:4:
summer.hpp:8:3: note: candidate: ‘template<class Iter, class, class T> T summer(Iter, Iter)’
8 | T summer(Iter start, Iter end)
| ^~~~~~
summer.hpp:8:3: note: template argument deduction/substitution failed:
summer.hpp:5:5: error: dependent-name ‘std::is_arithmetic<_Tp>::value_type’ is parsed as a non-type, but instantiation yields a type
5 | typename = typename std::enable_if_t<std::is_arithmetic<Iter>::value_type, Iter>,
| ^~~~~~~~
summer.hpp:5:5: note: say ‘typename std::is_arithmetic<_Tp>::value_type’ if a type is meant
我相信我已经把typename 放在了正确的地方,如果我想摆脱算术限制编译就好了,但是我不希望它接受例如string 向量。
我做错了什么?
【问题讨论】:
-
那里似乎有一条说明告诉你如何修复它。
-
请注意,
Iter可能并不总是直接有一个::value_type——毕竟指针是一个迭代器。你真正想要的是std::iterator_traits<Iter>::value_type。您还想检查此值类型是否为算术类型,因为目前您正在检查Iter本身是否为算术类型。 -
@1201ProgramAlarm 你指的是
note: say ‘typename std::is_arithmetic<_Tp>::value_type’ if a type is meant吗?那是行不通的,不是吗?这应该返回bool,而不是typename。 -
为了满足我自己的好奇心:一个使用概念的C++20 version。相当漂亮。
-
@NathanPierson 看起来很酷,为什么不把它作为答案呢?
标签: c++ c++11 templates c++17 sfinae