I am trying to create a convenience function my::find that wraps the std::find for the std::vector type. It may be not very useful, but it makes code a bit cleaner. Unfortunately I am not able to make the return type work. See the example:
#include <vector>
namespace my {
template<typename T>
inline typename std::vector<T>::iterator::type find(const std::vector<T>& vector, const T& value)
{
return std::find(vector.begin(), vector.end(), value);
}
template<typename T>
inline bool contains(const std::vector<T>& vector, const T& value)
{
return std::find(vector.begin(), vector.end(), value) != vector.end();
}
}
bool a() {
std::vector<float> v;
float a = 0.0f;
auto found = my::find(v, a);
return found != v.end();
}
bool b() {
std::vector<float> v;
float a = 0.0f;
return my::contains(v, a);
}
I have also created a similar my::contains function, which works fine.
When I am trying to use my::find I get the error:
[x64 msvc v19.16 #1] error C2672: 'my::find': no matching overloaded function found
[x64 msvc v19.16 #1] error C2893: Failed to specialize function template 'std::vector<T,std::allocator<_Ty>>::iterator::type my::find(const std::vector<T,std::allocator<_Ty>> &,const T &)'
[x64 msvc v19.16 #1] note: With the following template arguments:
[x64 msvc v19.16 #1] note: 'T=float'
Here's a godbolt for it: https://godbolt.org/z/ri_xoV
You messed up something with return type. This should work:
#include <vector>
namespace my {
template<typename T>
inline typename std::vector<T>::const_iterator find(const std::vector<T>& vector, const T& value)
{
return std::find(vector.begin(), vector.end(), value);
}
template<typename T>
inline bool contains(const std::vector<T>& vector, const T& value)
{
return std::find(vector.begin(), vector.end(), value) != vector.end();
}
}
bool a() {
std::vector<float> v;
float a = 0.0f;
auto found = my::find(v, a);
return found != v.end();
}
bool b() {
std::vector<float> v;
float a = 0.0f;
return my::contains(v, a);
}
If you are using C++14, then this is even better.
#include <vector>
namespace my {
template<typename T>
inline auto find(const std::vector<T>& vector, const T& value)
{
return std::find(vector.begin(), vector.end(), value);
}
template<typename T>
inline bool contains(const std::vector<T>& vector, const T& value)
{
return std::find(vector.begin(), vector.end(), value) != vector.end();
}
}
Don't even bother specifying the return type and there will be no errors. Less typing too!
Related
What I am doing
I am practicing c++ after 3 years. I needed to learn fast and broadly, so this example i am trying to solve might look odd to you.
I am using c++20, gcc 10.2.
I wanted to make a pythonic enumerate function that
Takes any container<T>
Yields std::tuple<int, T>
Where T is the type of items in the container
I wanted to try applying pythonic range as an argument of enumerate which
Takes (int start, int end, int step)
Yields int i from start to end every step
range (Not my code, I only added step functionality)
template <typename T>
class range_iterator;
template <typename T>
class range_impl
{
const T start_;
const T stop_;
const T step_;
public:
range_impl(T start, T stop, T step) : start_{start}, stop_{stop}, step_{step} {};
range_impl(T start, T stop) : start_{start}, stop_{stop}, step_{1} {};
range_impl(T stop) : start_{0}, stop_{stop}, step_{1} {};
range_iterator<T> begin() const
{
return range_iterator<T>{start_, step_};
}
range_iterator<T> end() const
{
return range_iterator<T>{stop_, step_};
}
};
template <typename T>
class range_iterator
{
T current_;
const T step_;
public:
range_iterator(T init, T step) : current_{init}, step_{step} {};
range_iterator<T> &operator++()
{
current_ += step_;
return *this;
}
bool operator!=(const range_iterator<T> &rhs) const
{
return current_ != rhs.current_;
}
T operator*() const
{
return current_;
}
};
template <typename T>
range_impl<T> range(const T start, const T stop, const T step)
{
return range_impl<T>(start, stop, step);
}
template <typename T>
range_impl<T> range(const T start, const T stop)
{
return range_impl<T>(start, stop);
}
template <typename T>
range_impl<T> range(const T stop)
{
return range_impl<T>(stop);
}
Can be used like following
#include <iostream>
int main()
{
for(auto i: range(0, 100 2)
{
std::cout << i << std::endl;
}
}
Problem code: enumerate
template <typename T>
class enumerate_iterator;
// Here, T should be a type of a container that contains type X
template <typename T>
class enumerate_impl
{
T impl;
public:
enumerate_impl<T>(T impl) : impl{impl} {/* empty */};
enumerate_iterator begin() const
{
return enumerate_iterator{impl.begin()};
}
enumerate_iterator end() const
{
return enumerate_iterator{impl.end()};
}
};
// Here, T should be a type of a iterator, I think. Confused myself.
template <typename T>
class enumerate_iterator
{
T iterator;
int i;
public:
enumerate_iterator(T iterator) : iterator{iterator}, i{0} {/* empty body */};
enumerate_iterator<T> &operator++()
{
i++;
iterator++;
return *this;
}
bool operator!=(const enumerate_iterator<T> &rhs) const
{
return iterator != rhs.iterator;
}
std::tuple operator*() const
{
return {i, *iterator};
}
};
template <typename T>
enumerate_impl<T> enumerate(T impl)
{
return enumerate_impl<T>{impl};
}
Expected usage
#include <iostream>
int main()
{
for (auto &[i, j] : enumerate(range(0, 100, 2)))
{
std::cout << i << " " << j << std::endl;
}
}
Gotten error (There actually tons of compilation error, but I want to try more on the others).
utility.cpp:186:20: error: deduced class type 'tuple' in function return type
186 | std::tuple operator*() const
I guessed this is complaining that you didn't tell me what type the tuple contains. But the thing is, I don't know what type T iterator contains. How would I tell return type is std::tuple<int, type T contains>?
Thanks for reading this long long question.
I think that perhaps, for enumerate_iterator, you might want its template type T to be a "base element type", not some compound "iteration type".
For example, if you were to choose to implement your iteration using raw memory pointers, then the enumerate_iterator's data member called iterator would have type T* (instead of its current T type).
And then, in that case, the definition of operator*() would be programmed as having a return type of std::tuple<int,T>
I have this code:
template <typename Iter>
class map_iterator : public std::iterator<std::bidirectional_iterator_tag, typename Iter::value_type::second_type> {
public:
map_iterator() {}
map_iterator(Iter j) : i(j) {}
map_iterator& operator++() { ++i; return *this; }
map_iterator operator++(int) { auto tmp = *this; ++(*this); return tmp; }
map_iterator& operator--() { --i; return *this; }
map_iterator operator--(int) { auto tmp = *this; --(*this); return tmp; }
bool operator==(map_iterator j) const { return i == j.i; }
bool operator!=(map_iterator j) const { return !(*this == j); }
reference operator*() { return i->second; }
pointer operator->() { return &i->second; }
protected:
Iter i;
};
template <typename Iter>
inline map_iterator<Iter> make_map_iterator(Iter j) { return map_iterator<Iter>(j); }
using route_departure_container = std::map<packed_time, route_departure_o>;
template <typename Iter>
using route_departure_const_iterator = map_iterator;
route_departure_const_iterator departure_at(const std::pair<key, const platform_route_o&>& pr, packed_time tm);
I have map using route_departure_container = std::map<packed_time, route_departure_o>; and I want to iterate through this map in a way that the iterator would reference only on the value and not the pair<key, value>.
The problem I have is in the last line route_departure_const_iterator departure_at(const std::pair<key, const platform_route_o&>& pr, packed_time tm); where route_departure_const_iterator is underlined with red and it says: argument list for alias template "route_departure_const_iterator" is missing.
I tried to insert template <typename Iter> above this line but it did not help. What should I do?
The same way you wrote the above declaration:
template <typename Iter>
inline map_iterator<Iter> make_map_iterator(Iter j) { return map_iterator<Iter>(j); }
You also need to write your problematic declaration:
template <typename Iter>
route_departure_const_iterator<Iter> departure_at(const std::pair<key, const platform_route_o&>& pr, packed_time tm);
Because the way you defined route_departure_const_iterator is just a plain, non-const alias to map_iterator, so you use it the same.
In my projects I'm using boost-variant exhaustively. Hence, for my unit tests I need to check the contents of a variant against a certain T with a certain content t.
So I deviced the function cmpVariant for this sole purpose and to remove clutter from my unit tests.
In some cases the type T is not equipped with an operator==, so that the user might pass a function satisfying the EqualityCompare Requirement (https://en.cppreference.com/w/cpp/named_req/EqualityComparable)
Now for some obscure reason the following code fails to compile. It says, that there is no matching function?
Clang 6.0.1 Compiler Error
prog.cc:22:5: error: no matching function for call to 'cmpVariant'
cmpVariant(number, 3.2, lambdaEquiv); // Fails!
^~~~~~~~~~
prog.cc:6:6: note: candidate template ignored: could not match 'function<bool (const type-parameter-0-1 &, const type-parameter-0-1 &)>' against '(lambda at prog.cc:19:24)'
bool cmpVariant(
^
1 error generated.
Does anyone knows why?
Code
#include <iostream>
#include <boost/variant.hpp>
#include <functional>
template<typename V, typename T>
bool cmpVariant(
const V& variant,
const T& t,
const std::function<bool(const T& u, const T& v)>& equiv = [](const T& u, const T& v) {return u == v; })
{
if (variant.type() != typeid(t)) return false;
auto v = boost::get<T>(variant);
return equiv(v, t);
}
int main(int, char**) {
boost::variant<double, int> number{ 3.2 };
cmpVariant(number, 3.2);
auto lambdaEquiv = [](const double& x, const double& y) { return x == y; };
std::function<bool(const double&, const double&)> equiv = lambdaEquiv;
cmpVariant(number, 3.2, equiv); // Works!
cmpVariant(number, 3.2, lambdaEquiv); // Fails!
}
The compiler is not able to match the lambda to the function parameter type. You can fix this by explicitly instantiating the function call:
cmpVariant<boost::variant<double, int>, double>(number, 3.2, equiv);
This is clearly a bit wordy, so here is another possibility changing your function declaration to
template<typename V, typename T, typename Fct = std::function<bool(const T& u, const T& v)>>
bool cmpVariant(
const V& variant,
const T& t,
Fct&& f = [](const T& u, const T& v) {return u == v; })
{ /* Same as before. */ }
which can be called like this
cmpVariant(number, 3.2, equiv); // Type deduction works now.
An improvement suggested by #DanielLangr in the comments is to employ std::equal_to.
template<typename V, typename T, typename Fct = std::equal_to<T>>
bool cmpVariant(
const V& variant,
const T& t,
Fct&& f = std::equal_to<T>{})
{ /* Again, same as before. */ }
One advantage here is to get rid of std::function and its often unnecessary overhead.
The way comparator argument is accepted makes deduction problematic, so you may want to change comparator into template parameter (possibly avoiding construction of heavy std::function object ):
template<typename T> class t_EquilityComparator
{
public: bool operator ()(const T& u, const T& v) const { return u == v; }
};
template<typename V, typename T, typename Comparator = t_EquilityComparator<T>>
bool cmpVariant(
const V& variant,
const T& t,
const Comparator & equiv = Comparator{})
{
if (variant.type() != typeid(t)) return false;
auto v = boost::get<T>(variant);
return equiv(v, t);
}
int main(int, char**) {
boost::variant<double, int> number{ 3.2 };
cmpVariant(number, 3.2);
auto equiv = [](const double& x, const double& y) { return x == y; };
cmpVariant(number, 3.2, equiv); // This line fails to compile! Why?
}
online compiler
#include "stdafx.h"
#include <algorithm>
class MyClass {
};
template <typename C, typename V, typename Enable = void>
static bool Contains(const C& container, const V& value) {
auto iter = std::find(container.begin(), container.end(), value);
auto result = (iter != container.end());
return result;
}
template <typename C, typename V,
typename std::enable_if<std::is_same<std::reference_wrapper<const V>, typename C::value_type>::value, bool>::type>
static bool Contains(const C& container, const V& value) {
auto iter = std::find_if(container.begin(), container.end(), [&](auto& aValue) {
return (aValue.get() == value);
});
auto result = (iter != container.end());
return result;
}
int main() {
const MyClass a;
auto container = {
std::reference_wrapper<const MyClass>(a),
};
Contains(container, a);
return 0;
}
Compiler: VC++2015U3
Compile error:
Severity Code Description Project File Line Suppression State
Error C2678 binary '==': no operator found which takes a left-hand
operand of type 'const std::reference_wrapper' (or
there is no acceptable conversion) ConsoleApplication1 c:\program
files (x86)\microsoft visual studio 14.0\vc\include\xutility 3258
It runs into the first implementation rather than the second one.
Any idea about this?
Maybe you need also an operator==() for MyClass but, to solve the specialization problem, I think is better to use an explicit specialization
template <template <typename...> class C, typename V>
static bool Contains (C<std::reference_wrapper<V const>> const & container,
V const & value) {
auto iter = std::find_if(container.begin(), container.end(), [&](auto& aValue) {
return (aValue.get() == value);
});
auto result = (iter != container.end());
return result;
}
instead of SFINAE.
Because if you also make SFINAE works to enable the reference-wrapper-container version, by example
template <typename C, typename V>
static std::enable_if_t<std::is_same<std::reference_wrapper<const V>,
typename C::value_type>::value, bool>
Contains (const C& container, const V& value)
both versions of Contains() function matches the call
Contains(container, a);
and no one is preferred.
You need to define operator == to compare class instances:
bool operator ==(MyClass const & left, MyClass const & right) { return false; }
This operator will be invoked by std::find and std::find_if algorithms (rather inside of lambda return (aValue.get() == value); in the second case).
I need to use a function template which is available in a header file via a function pointer which is available as a struct member.
For example:
File: mytemplate.h
template<typename T> const bool GT(const T& pa_roIN1, const T& pa_roIN2)
{
bool temp = false;
if(pa_roIN1 > pa_roIN2){
temp = true;
}
return temp;
}
template<typename T> const bool EQ(const T& pa_roIN1, const T& pa_roIN2)
{
bool temp = false;
if(pa_roIN1 == pa_roIN2){
temp = true;
}
return temp;
}
template<typename T> const bool GE(const T& pa_roIN1, const T& pa_roIN2)
{
bool temp = false;
if(pa_roIN1 >= pa_roIN2){
temp = true;
}
return temp;
}
File: mystruct.h:
struct mystruct {
std::string funcName;
bool (*funcPtr)(int,int);
};
typedef std::map<int, mystruct> mystructList;
File: mycpp.cpp:
#include "mytemplate.h"
#include "mystruct.h"
mystruct MyGreaterStruct[3] = {
{"GREATER_THAN", >},
{ "EQUAL", &EQ},
{ "GREATER_N_EQUAL", &GE}
};
mystructList MyList;
int main(void)
{
int size = sizeof(MyGreaterStruct)/sizeof(mystruct);
for(int i = 0; i < size; i++) {
MyList.insert(std::pair<int, mystruct>(i,MyGreaterStruct[i])); }
for(mystructList::iterator iter = MyList.begin(); iter != MyList.end(); iter++) {
printf("\nResult of func : %s for values 100,50 : %d",iter->second.funcName.c_Str(),iter->second->funcPtr(100,50));
}
}
I am not sure this the correct way of doing it. But there is no result that gets printed on the console.
The error you get when compiling your code tells you what is wrong:
mycpp.cpp:8:1: error: no matches converting function ‘GT’ to type ‘bool (*)(int, int)’
};
^
mytemplate.h:1:33: note: candidate is: template<class T> const bool GT(const T&, const T&)
template<typename T> const bool GT(const T& pa_roIN1, const T& pa_roIN2)
^
There's no way to instantiate that template to match the signature of the function pointer, as the template takes two references as arguments, while the pointer takes two ints. If you can't change either the struct or the templates, and you are using C++11, you could try using lambdas instead:
mystruct MyGreaterStruct[3] = {
{"GREATER_THAN", [](int a, int b)->bool { return GT(a, b); } },
{ "EQUAL", [](int a, int b)->bool { return EQ(a, b); } },
{ "GREATER_N_EQUAL", [](int a, int b)->bool { return GE(a, b); } }
};
but no matter how you slice it, you need to either change the arguments or use a little function that converts the arguments from one form to the other.