I'm trying to teach myself the SFINAE pattern and for a thing I'm writing I wanted to write a function that accepts start
, end
iterators to a value of an arithmetic type (e.g. for summing). This is what I came up with:
My 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;
}
and then 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;
}
The SFINAE bit above I took from this answer and just tweaked it to use the type trait that corresponds to the type an iterator points to (value_type
). But I'm struggling to compile it, I'm getting a barrage of complaints about value_type
being parsed as a non-type but yielding a type and hints that I should prefix it with adding typename
(which is wrong):
$ 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
I believe I've put typename
in the correct places, if I was to get rid of the arithmetic restrictions compiles just fine but then I don't want it to accept e.g. string
vectors.
What am I doing wrong?
Aucun commentaire:
Enregistrer un commentaire