Can't Pass Enum Value to Recursive Template (C++) - c++

Suppose I want to write a recursive template function that compares an individual value to every single element in an n-dimensional vector, returning true if there is at least one match and false if there are none.
I wrote some code to do this, although it's probably far from optimal:
template <typename T, typename Checker>
void check_for_each(const T& v, const Checker condition)
{
condition(v);
}
template <typename T, typename Checker>
void check_for_each(const std::vector<T>& v, const Checker condition)
{
for(unsigned int i = 0; i < v.size(); i++)
{
check_for_each(v[i], condition);
}
}
template <typename T, typename U>
bool is_equal_any(const T& VALUE, const std::vector<typename U> VECTOR)
{
bool is_equal = false;
check_for_each(VECTOR, [&is_equal, &VALUE](const T& val)
{
if(!is_equal && VALUE == val)
{
is_equal = true;
}
});
return is_equal;
}
While this seems to work, I've encountered an unusual issue and I can't quite understand it. For example, the following code works:
enum PIECE_NAME {EMPTY, PAWN, ROOK, KNIGHT, BISHOP, QUEEN, KING};
std::vector<std::vector<int>> board {{ROOK, BISHOP}, {KNIGHT, QUEEN}};
std::cout << is_equal_any(2, board); // outputs 1 (there is a rook on the board)
Yet the following, slight change does not:
std::cout << is_equal_any(ROOK, board); // compile error C2664
Apparently my function cannot figure out how to convert the enum value to an integer. Of course, I can just use static_cast<int>(ROOK), and the code compiles and runs as expected, but that's obviously not ideal. Furthermore, I know that I can change my board's declaration to std::vector<std::vector<PIECE_NAME>> board, (which also runs as expected) but I'd prefer to leave it at int. So is it possible to rewrite these recursive template functions so that is_equal_any can take enum values directly? I'm still very new to C++, so I would really appreciate as much detail in your answer as possible. Thank you.

The problem arises from the type T here:
check_for_each(VECTOR, [&is_equal, &VALUE](const T& val)
^
By calling
is_equal_any(ROOK, board)
T is a PIECE_NAME, but what you are finally passing as parameter to this lambda are the elements of your vector of type int. But an int can't be implicitly converted to an enum.
You can't either use directly U as it could be a std::vector<int> or std::vector< std::vector<int> > or...
If you were using C++14, you could use a generic lambda with auto:
check_for_each(VECTOR, [&is_equal, &VALUE](const auto& val)
But as you tagged your question C++11, you can use a trait:
template <typename T>
struct leaf_type {
using type = T;
};
template <typename T>
struct leaf_type<std::vector<T>> {
using type = typename leaf_type<T>::type;
};
template <typename T>
using leaf_type_t = typename leaf_type<T>::type;
usage:
check_for_each(VECTOR, [&is_equal, &VALUE](const leaf_type_t<U> & val)
DEMO
Btw you should avoid nested std::vectors and linearize it into a single one like:
std::vector<int> board {ROOK, BISHOP, KNIGHT, QUEEN};
Then you can easily use std::find.

This is kind of an XY problem, as there are better approaches:
Use a scoped enum
don't mix integers and enums
delegate your work to std::any_of
For example:
namespace multi_dim{
template< class InputIt, class UnaryPredicate >
bool any_of(InputIt first, InputIt last, UnaryPredicate p)
{
using std::any_of;
for(;first != last; ++first)
{
bool next = any_of(first->cbegin(), first->cend(), p);
if (next)
return true;
}
return false;
}
}
Demo
A test:
std::vector<std::vector<PIECE>> board {{PIECE::ROOK, PIECE::BISHOP}, {PIECE::KNIGHT, PIECE::QUEEN}};
std::cout << std::boolalpha << multi_dim::any_of(board.cbegin(), board.cend(), [](PIECE p){return p == PIECE::ROOK;}) << std::endl;
std::cout << std::boolalpha << multi_dim::any_of(board.cbegin(), board.cend(), [](PIECE p){return p == PIECE::EMPTY;}) << std::endl;
Output:
true
false

Wild guess: Try a difference template parameter for VALUE and for the element type of VECTOR.
I don't use MSVC so I'm not sure exactly what error you're getting.
... regardless of all that, I just have to repeat my comment: Please don't write this kind of code.

Although the solution using std::any_of is the best one, I give my answer that show somewhat less drastic improvement to original code.
template <typename T, typename Checker>
bool check_for_each(const T& v, const Checker condition)
{
return condition(v);
}
template <typename T, typename Checker>
bool check_for_each(const std::vector<T>& v, const Checker condition)
{
return std::find_if(begin(v), end(v), [condition](const T &t) { return check_for_each(t, condition); }) != v.end();
}
template <typename T, typename U>
bool is_equal_any(const T& value, const U &container)
{
return check_for_each(container, [&value](const T& val){ return value == val; });
}
enum class PIECE_NAME { EMPTY, PAWN, ROOK, KNIGHT, BISHOP, QUEEN, KING };
void test()
{
std::vector<std::vector<PIECE_NAME>> board
{
{ PIECE_NAME::ROOK, PIECE_NAME::BISHOP },
{ PIECE_NAME::KNIGHT, PIECE_NAME::QUEEN }
};
std::cout << is_equal_any(PIECE_NAME::ROOK, board);
}
This solution is still hard-coded for nested vectors but the code has been simplified a bit and also optimized as it will stop searching once an item is found.
As already suggested in other comments, you should really use enum (or better yet enum class). It does not make much sense to store integers in the vector as you loose type information.

Related

generic iterators to access elements of vectors without using Templates c++

I am creating a function which should take as input iterators to vector
for example:
vector<int> a;
foo(a.begin(),a.end())
The vector can hold any type.
Now the simple way to do this is using templates
template <typename Iterator>
void foo(Iterator first, Iterator last) {
for (Iterator it = first; it!=last; ++it) {
cout << *it;
}
}
I want to know if there is a way to achieve the same functionality without using templates. Since using Templates would force me to include these functions in Header file of a public API which I don't want to. So I wanted to know is there an alternate way to access the iterators without using Templates.
There are ways not to include the implementation in header files but they are not clean to implement (for instance you should know in advance the instantiations). Read here for more info about this issue:
Why can’t I separate the definition of my templates class from its declaration and put it inside a .cpp file?
How can I avoid linker errors with my template functions?
For instance in:
foo.h
#ifndef HI_
#define HI_
template<class Iterator>
void foo(Iterator first, Iterator last);
#endif
foo.cpp
#include "stack.h"
using namespace std;
template<class Iterator>
void foo(Iterator first, Iterator last) {
for (Iterator it = first; it != last; ++it) {
cout << *it << " ";
}
}
template
void foo( std::vector<int>::iterator first, std::vector<int>::iterator last);
template
void foo( std::vector<double>::iterator first, std::vector<double>::iterator last);
Now you can use foo function only for double and int. Other types won't link.
Hope this helps.
This is a long answer. The short answer is "type erasure"; go learn about it.
The long answer is two answers. First I cover "do you just want to be able to iterate over contiguous ints?". Then you want span. This is a really simple form of type erasure that forgets what the exact container is you are working on so long as it is contiguous and over T.
The second answer is if you actually need to deal with multiple types (not just int) and multiple kinds of containers (not just contiguous ones).
The two answers are separated by a line.
The span concept (see gsl::span) is designed for pretty much this reason. It itself is a template (over the type you are working with), but it will be a concrete instance of a template in most interfaces.
Here is a toy version of it:
template<class T>
struct span_t {
T* b = 0;
T* e = 0;
T* begin() const { return b; }
T* end() const { return e; }
span_t(span_t const&)=default;
span_t& operator=(span_t const&)=default;
span_t()=default;
span_t( T* s, T* f ):b(s),e(f) {}
span_t( T* s, std::size_t l):span_t(s, s+l){}
template<std::size_t N>
span_t( T(&arr)[N] ):span_t(arr, N) {}
std::size_t size() const { return end()-begin(); }
bool empty() const { return begin()==end(); }
T& front() const { return *begin(); }
T& back() const { return *(std::prev(end()); }
T* data() const { return begin(); }
span_t without_front( std::size_t N=1 ) const {
return {std::next( begin(), (std::min)(N, size()) ), end()};
}
span_t without_back( std::size_t N=1 ) const {
return {begin(), std::prev(end(), (std::min)(N, size()) )};
}
};
we can augment it with conversion operators
namespace details {
template<template<class...>class Z, class, class...Ts>
struct can_apply:std::false_type{};
template<class...>using void_t=void;
template<template<class...>class Z, class...Ts>
struct can_apply<Z, void_t<Z<Ts...>>, Ts...>:std::true_type{};
}
template<template<class...>class Z, class...Ts>
using can_apply = details::can_apply<Z,void,Ts...>;
template<class C>
using dot_data_r = decltype( std::declval<C>().data() );
template<class C>
using dot_size_r = decltype( std::declval<C>().size() );
template<class C>
using can_dot_data = can_apply< dot_data_r, C >;
template<class C>
using can_dot_size = can_apply< dot_size_r, C >;
can_dot_data detects via SFINAE if .data() is valid to do on an object of type C.
Now we add a constructor:
template<class T,
std::enable_if_t<
can_dot_data<T&>{}
&& can_dot_size<T&>{}
&& !std::is_same<std::decay_t<T>, span_t>{}
, int
> =0
>
span_t( T&& t ): span_t( t.data(), t.size() ) {}
which covers std::vector and std::string and std::array.
Your function now looks like:
void foo(span_t<int> s) {
for (auto&& e:s)
std::cout << s;
}
}
with use:
std::vector<int> a;
foo(a);
now, this only works for contiguous containers of a specific type.
Suppose this is not what you want. Maybe you do need to solve this for a myriad of types, and you don't want to expose everything in the header.
Then what you need to do is known as type erasure.
You need to work out what minimal set of operations you need from the provided types. Then you need to write wrappers that "type erase" these operations down to "typeless" operations.
This goes in the header, or in another helper header.
In the interface of the function, or in a header intermediate helper, you take the incoming types and do the type erasure, then pass the type-erased types into the "real" implementation.
An example of type erasure is std::function. It takes almost anything that can be invoked with a fixed signature, and turns it into a single type-erased type. Everything except how to copy, destroy and invoke an instance of the type is "forgotten" or erased.
For your case:
template <typename Iterator>
void foo(Iterator first, Iterator last) {
for (Iterator it = first; it!=last; ++it) {
cout << *it;
}
}
I see two things that need to be erased down to; iteration, and printing.
struct printable_view_t {
void const* data = 0;
void(*print_f)(std::ostream& os, void const*) = 0;
explicit operator bool()const{return data;}
printable_view_t() = default;
printable_view_t(printable_view_t const&) = default;
template<class T,
std::enable_if_t<!std::is_same<T, printable_view_t>{}, int> =0
>
printable_view_t( T const& t ):
data( std::addressof(t) ),
print_f([](std::ostream& os, void const* pv){
auto* pt = static_cast<T const*>(pv);
os << *pt;
})
{}
std::ostream& operator()(std::ostream& os)const {
print_f(os, data);
return os;
}
friend std::ostream& operator<<(std::ostream& os, printable_view_t p) {
return p(os);
}
};
printable_view_t is an example of type-erasing "I can be printed".
void bar( printable_view_t p ) {
std::cout << p;
}
void test_bar() {
bar(7);
bar(3.14);
bar(std::string("hello world"));
}
The next thing we'd have to do is type erase iteration. This is harder, because we want to type erase iteration over iterating over a printable_view_t type.
Type erasing foreach is a tad easier, and often more efficient.
template<class View>
struct foreach_view_t {
void* data = 0;
void(*func)( std::function<void(View)>, void* ) = 0;
explicit operator bool()const{return data;}
foreach_view_t() = default;
foreach_view_t(foreach_view_t const&) = default;
template<class T,
std::enable_if_t<!std::is_same<std::decay_t<T>, foreach_view_t>{}, int> =0
>
foreach_view_t( T&& t ):
data( const_cast<std::decay_t<T>*>(std::addressof(t)) ),
func([](std::function<void(View)> f, void* pv){
auto* pt = static_cast<std::remove_reference_t<T>*>(pv);
for (auto&& e : *pt)
f(decltype(e)(e));
})
{}
void operator()(std::function<void(View)> f)const{
func(f, data);
}
};
we then daisy chain these together
void foo(foreach_view_t<printable_view_t> x) {
x([](auto p){ std::cout << p; });
}
test code:
std::vector<int> a{1,2,3};
foo(a);
Now much of the header code was "hoisted" into the type erasure types instead of a function template body. But careful choice of the points of type erasure can let you keep what you need from the types precise and narrow, and the logic of how you use those operations private.
As an example, the above code doesn't care where you are printing it to; std::cout was not part of the type erasure.
Live example.
I want to know if there is a way to achieve the same functionality without using templates. [...] I wanted to know is there an alternate way to access the iterators without using Templates.
Yes, if you use C++14, but...
Since using Templates would force me to include these functions in Header file of a public API which I don't want to.
... isn't a useful way for you because it's equivalent to use templates and you have to put it in the header file.
In C++14 you can use a lambda function with auto parameters.
auto foo = [](auto first, auto last)
{ for (auto it = first ; it != last; ++it ) std::cout << *it; };
The autos aren't template (from a formal point of view) but are equivalent and you can't declare foo in the header and develop it in a cpp file.

Comparer that takes the wanted attribute

In order to use a standard function like std::sort on some standard container Container<T>
struct T{
int x,y;
};
based on the y value, you need to write something like (for example):
std::vector<T> v;
//fill v
std::sort(v.begin(),v.end(),[](const auto& l,const auto& r){
return l.y<r.y;
});
The comparer that was written as lambda function is used too much and re-written again and again during the code for various classes and attributes.
Considering the case where y's type is comparable (either like int or there is an overload for the < operator), is there any way to achieve something like:
std::sort(v.begin(),v.end(),imaginary::less(T::y)); // Imaginary code
Is it possible in C++ to write such a function like less? or anything similar?
I am asking because I remember something like that in some managed language (I am not sure maybe C# or Java). However, I am not sure even about this information if it is true or not.
template<typename T, typename MT>
struct memberwise_less
{
MT T::* const mptr;
auto operator()(const T& left, const T& right) const
{ return (left.*mptr) < (right.*mptr); }
};
template<typename T, typename MT>
memberwise_less<T, MT> member_less(MT T::*mptr)
{
return { mptr };
}
and then you can do
std::sort(v.begin(), v.end(), member_less(&T::y));

Creating an iterator to a map in a class template

I have this class template which contains a map as following:
template<class K, class V>
class interval_map {
private:
std::map<K,V> m_map;
}
And I want to have a function that adds values to the maps and checks whether the key already exists or not so I am trying to do this using iterator :
void add_elements_test2 ( K const& key,V const& val)
{
std::make_pair<typename std::map<K,V>::iterator,bool>x;
x= m_map.insert(std::make_pair(key,val));
if(x.second = false)
{
cout<<"Key alreads exists "<<endl;
}
}
but I get this error when I create the operator:
std::make_pair<typename std::map<K,V>::iterator,bool>x;
Is this is a correct way?
std::make_pair<typename std::map<K,V>::iterator,bool>x;
It not correct the correct way to declare a std::pair. If you want to declare a std::pair for the return of insert then you need
std::pair<typename std::map<K,V>::iterator,bool> x;
And now x has the correct type. std::make_pair is a function that is used to construct a std::pair and you pass it the variables to make the pair from.
Instead of having to type all this though you can simply use auto like
auto x = m_map.insert(std::make_pair(key,val));
//...
Now x has the correct type and you do a lot less typing.
You also have a typo in
if(x.second = false)
In the above you are doing assignment, not comparison. Since you are setting the value to false the if statement will never run as it will always evaluate to false. You need
if(x.second == false)
Simply use auto:
auto x = m_map.insert(std::make_pair(key, val));
if (!x.second)
{
cout << "Key already exists" << endl;
}
Note: the type you want is pair
std::pair<typename std::map<K, V>::iterator, bool>
std::make_pair is an utility function to create std::pair.
I wrote this answer so that you don't hate template classes in the future. There are 2 scenarios you need to consider, and I have listed them both in the code below. Let me know if you have any questions, the comments are detailed.
Scenario 1, add_elements_test2 is defined inside the class
template<class K, class V>
class interval_map {
private:
std::map<K,V> m_map;
// This is fine because the K and V types are in the same scope for the map, and add_elements_test2
void add_elements_test2 ( K const& key,V const& val)
{
// Use auto here to simplify your life a little
auto x = m_map.insert(std::make_pair(key,val)); // actual type is std::pair<K, bool>
if(x.second == false)
{
cout<<"Key already exists "<<endl;
}
}
};
Scenario 2, add_elements_test2 is defined outside the class
template<class K, class V>
class interval_map {
private:
std::map<K,V> m_map;
void add_elements_test2 ( K const& key,V const& val);
};
// need another template
template<class K, class V>
// need to template interval_map, this could cause headaches if you did not realize this is a templated class
void interval_map<K, V>::add_elements_test2 ( K const& key,V const& val)
{
// Use auto here to simplify your life a little
auto x = m_map.insert(std::make_pair(key,val)); // actual type is std::pair<K, bool>
if(x.second == false)
{
cout<<"Key already exists "<<endl;
}
}
Essentially, your mistake with x is the type definition.
// pair is in the utility header
std::pair<K, bool> x= m_map.insert(std::make_pair(key,val));

equal_range and range for

While discussing multimap with my students, I noticed a small change that could cut out a bit of boilerplate, and was wondering if anyone had suggested it to the standard committee, and if so what the response was.
The canonical method of iterating over an equal range is (taken from cplusplus.com):
// multimap::equal_range
#include <iostream>
#include <map>
int main ()
{
std::multimap<char,int> mymm;
mymm.insert(std::pair<char,int>('a',10));
mymm.insert(std::pair<char,int>('b',20));
mymm.insert(std::pair<char,int>('b',30));
mymm.insert(std::pair<char,int>('b',40));
mymm.insert(std::pair<char,int>('c',50));
mymm.insert(std::pair<char,int>('c',60));
mymm.insert(std::pair<char,int>('d',60));
std::cout << "mymm contains:\n";
for (char ch='a'; ch<='d'; ch++)
{
std::pair <std::multimap<char,int>::iterator,std::multimap<char,int>::iterator> ret;
ret = mymm.equal_range(ch);
std::cout << ch << " =>";
for (std::multimap<char,int>::iterator it=ret.first; it!=ret.second; ++it)
std::cout << ' ' << it->second;
std::cout << '\n';
}
return 0;
}
You cannot use a range based for loop directly in this case because the return type of equal_range is a pair<multimap<K,V>::iterator, multimap<K,V>::iterator>. However, a simple wrapping struct should allow this:
template <typename T>
struct abstract_collection {
abstract_collection(pair<T, T> its)
: m_begin(its.first),
m_end(its.second) {}
abstract_collection(T begin, T end)
: m_begin(begin),
m_end(end) {}
T begin() const { return m_begin; }
T end() const { return m_end; }
T m_begin;
T m_end;
};
Combined with adding a function to the multimap (and others) API to return iterators in this structure, rather than in a pair.
template<typename K, typename V, typename C, typename A>
auto multimap<K, V, C, A>::equal_range_c(K const& k) -> abstract_collection<iterator> {
return equal_range(k);
}
Or alternatively overloading a version of std::begin and std::end that takes a pair of iterators should work as well:
template <typename T>
T begin(pair<T, T> p) { return p.first; }
template <typename T>
T end(pair<T, T> p) { return p.second; }
Has these ideas surfaced before, and if so, what was the committee response? Are they just unworkable or undesirable for some reason I'm not seeing?
(Note, the code was written without attempting to compile or check for expositional purposes only. It's probably wrong. And it doesn't contain typechecking to constrain to iterators only as it ought to, as that was added complexity that didn't serve to explain the idea.)
This is what boost::iterator_range accomplishes, which was adopted into the range library TS as ranges::iterator_range. That TS is to be incorporated sometime after C++17.

Is a templated function that supports different levels of indirection possible in C++11?

Essentially, I'm curious if you can use C++11 templates to make it so a templated function can detect an iterator's level of indirection and compile the function differently depending on that. For example, here is some code that won't compile:
#include <vector>
#include <list>
#include <type_traits>
#include <iostream>
struct MyStruct
{
int value;
MyStruct(int value = 42) : value(value) { }
const int& getInt() const { return value; }
};
typedef std::list<MyStruct> StructList;
typedef std::vector<const MyStruct*> StructPtrVector;
template <typename ITER_TYPE>
const int& getIteratorInt(ITER_TYPE iter)
{
if (std::is_pointer<decltype(*iter)>::value)
return (*iter)->getInt(); // Won't compile -> MyStruct has no operator-> defined
return iter->getInt(); // Won't compile -> MyStruct* has the wrong level of indirection
}
template <typename LIST_TYPE>
void PrintInts(const LIST_TYPE& intList)
{
for (auto iter = intList.begin(); iter != intList.end(); ++iter)
std::cout << getIteratorInt(iter) << std::endl;
}
int main(void)
{
StructList structList;
StructPtrVector structPtrs;
int values[5] = { 1, 4, 6, 4, 1 };
for (unsigned i = 0; i < 5; ++i)
{
structList.push_back(values[i]);
structPtrs.push_back(&structList.back());
}
PrintInts(structList);
PrintInts(structPtrs);
return 0;
}
The obvious situation is when you have a list of objects, and then a different kind of list of pointers to objects. And, what you want to do is the same to both lists, by treating them both as lists of objects.
The above code won't compile, because it is doing a logical check that should be done at compile-time. I don't know if there is a way to do this with preprocessor macros. I tried a simple #if std::is_pointer<decltype(*iter)>::value == true, but the compiler seems to always consider it false. (I've never tried preprocessor macros much before, but that is clearly not the proper way.)
Any idea if it's even possible?
When you want to select between two implementations depending on a metafunction such as is_pointer, use std::enable_if, which works on the principle of SFINAE.
template <typename ITER_TYPE>
auto getIteratorInt(ITER_TYPE iter) ->
typename std::enable_if< std::is_pointer<
typename std::iterator_traits< ITER_TYPE >::value_type >::value,
const int& >::type
{
return (*iter)->getInt();
}
template <typename ITER_TYPE>
auto getIteratorInt(ITER_TYPE iter) ->
typename std::enable_if< ! std::is_pointer<
typename std::iterator_traits< ITER_TYPE >::value_type >::value,
const int& >::type
{
return iter->getInt();
}
This way, template instantiation only sees lines of code that are valid for the given template arguments.
I've just applied this fix to your code mechanistically… I'm not advocating the use of multiple indirection or suggesting that the fixed implementation is robust.