Automatic type inference in C++ - c++

I implemented a class filtered_ostream_iterator that helps to filter stream using predicate and I made it as a template class.
template<typename T, typename Pred>
class filtered_ostream_iterator
{
ostream& os;
Pred _filter;
public:
filtered_ostream_iterator(ostream & o, Pred filter): os(o),
_filter(filter) {}
filtered_ostream_iterator& operator++()
{
return *this;
}
filtered_ostream_iterator& operator*()
{
return *this;
}
filtered_ostream_iterator& operator=(T t)
{
if (_filter(t))
os << t;
return *this;
}
};
It's ok but now I have a problem. When I use filtered_ostream_iterator I have to define it in following way.
stringstream ss1;
auto filter = [](char t){ return (t >= 'a' && t <= 'z') || (t >= 'A' && t <= 'Z'); };
filtered_ostream_iterator<char, bool (*)(char)> it1(ss1, filter); // initialization
It looks not really good especially <char, bool (*)(char)>. Then I decided to make a special function that can automatically inference types.
template<typename Pred>
filtered_ostream_iterator<char, Pred> create_filtered_ostream_iterator(ostream& os, Pred pred)
{
return filtered_ostream_iterator<char, Pred>(os, pred); // problem
}
And I use it in following way
auto it1 = create_filtered_ostream_iterator(ss1, filter);
You can see that I should specify type of elements in stream and now it's not a template actually, but when I'm trying to replace the code below with some thing like this
template<typename Pred, typename T>
filtered_ostream_iterator<T, Pred> create_filtered_ostream_iterator(ostream& os, Pred pred)
{
return filtered_ostream_iterator<T, Pred>(os, pred); // error
}
And when I'm using it in the same way
auto it1 = create_filtered_ostream_iterator(ss1, filter);
I'm getting the following error.
error: no matching function for call to 'create_filtered_ostream_iterator'
So how should I avoid all these problems? Or should I use my first variant of definition and don't mind how hard it looks? What do you think about it?

Write it like this:
template <typename T, typename Pred>
filtered_ostream_iterator<T, Pred> create(std::ostream & os, Pred p)
{
return filtered_ostream_iterator<T, Pred>(os, p);
}
Usage:
auto it = create<char>(ss1, filter);
Only trailing template arguments can be deduced, but you're free to specify as many initial arguments as you like.
The alternative is to deduce the type from the stream:
template <typename TChar, typename TTraits, typename Pred>
filtered_ostream_iterator<typename TTraits::char_type, Pred>
create(std::basic_ostream<TChar, TTraits> & os, Pred & p)
{
return filtered_ostream_iterator<typename TTraits::char_type, Pred>(os, p);
}
Usage:
auto it = create(ss, filter);

Related

Template conflict for similar numerical types

I have a very simple function
template<typename T>
bool is_element(const std::vector<T> & vec, T el)
{
return (std::find(vec.begin(), vec.end(), el) != vec.end());
}
that is supposed to just check if an element exists in a vector. But I run into problems when for example el is an unsigned long and vec is an integer vector. The template types are different initially, but the same after implicit conversion. Is there any elegant way to deal incorporate implicit conversion into templates without doing a bunch of function overloading?
You could deduce T using the first parameter, while suppressing type-deduction in the second one by putting it in a non-deducible context:
template<class T>
struct suppress_deduction {
using type = T;
};
template<class T>
using suppress_deduction_t = typename suppress_deduction<T>::type;
template<typename T>
bool is_element(const std::vector<T> & vec, suppress_deduction_t<T> el)
{
return (std::find(vec.begin(), vec.end(), el) != vec.end());
}
Do you need to limit yourself to a single template type?
template<typename T, typename S>
bool is_element(const std::vector<T> & vec, S el)
{
return (std::find(vec.begin(), vec.end(), el) != vec.end());
}
You can make one parameter non deducible.
Following does that and also makes it more generic:
template <typename Container>
bool is_element(const Container& cont, const Container::value_type& e)
{
return (std::find(cont.begin(), cont.end(), e) != cont.end());
}

A template function for reading std::vector<T> from a stream

I have a template ReadVector function that reads std::vector from a stream:
template <class Stream, typename T>
inline void ReadVector(Stream & s, std::vector<T> & items)
{
s.Read(reinterpret_cast<uint8_t *>(items.data()), items.size() * sizeof(T));
}
with the specialization for boolean vector:
template <class Stream>
void ReadVector(Stream & s, std::vector<bool> & x)
{
...
}
the code above compiles, but I'd like to make the first function called only if T is an arithmetic type, so the condition should be like this:
std::enable_if<std::is_arithmetic<T>::value && !std::is_same(T, bool)::value
but I cannot figure out what is the syntax.
Also I'd like to have yet another specialization of ReadVector if T is not bool and is not arithmetic.
My first idea was something like this:
template <class Stream, typename T>
void ReadVector(Stream & s, std::vector<T> & items);
template <class Stream, typename T>
typename std::enable_if<std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, void>::type ReadVector(Stream & s, std::vector<T> & items)
{
...
}
but this results in ambiguous call to overloaded function.
Figured this out!
template <class Stream, typename T>
typename std::enable_if<std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, void>::type ReadVector(Stream & s, std::vector<T> & v)
{
s.Read(reinterpret_cast<uint8_t *>(v.data()), v.size() * sizeof(T));
}
template <class Stream, typename T>
typename std::enable_if<std::is_class<T>::value, void>::type ReadVector(Stream & s, std::vector<T> & v)
{
for (auto & elem : v)
{
Read(s, elem);
}
}
template <class Stream>
void ReadVector(Stream & s, std::vector<bool> & x)
{
...
}
I think your approach is wrong!
Why not just use the vector constructor?
std::vector<int> v(std::istream_iterator<int>(stream), std::istream_iterator<int>());
Don't need a function when it can be done in the vector initializer.
If you want to do something fancy (like read raw data from the stream) you just define a class for reading that specific type of data.
struct RawDataToInt
{
int value;
operator int() {return value;}
friend std::istream& operator>>(std::istream& str, RawDataToInt& v)
{
return str.read(reinterpret_cast<char*>(&v.value), sizeof(int));
}
};
....
std::vector<int> v(std::istream_iterator<RawDataToInt>(stream), std::istream_iterator<RawDataToInt>());

c++ template specialization for container of reference_wrapper

#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).

How to wrap a templated function to work on const and non-const data

I want to create a templated function that works the same way for const and non-const data, except that it returns a const or non-const pointer as appropriate.
For instance, I want to return a pointer to a matching element in a container:
template <class Container, class Pred>
typename Container::value_type* getValuePtrIf(Container& c, Pred pred)
{
auto it=std::find_if(c.begin(), c.end(), pred);
return (it!=c.end()) ? &(*it) : nullptr;
}
However I can't get this to build for const and non-const calls. If I omit the const from the Container& c declaration then it can't return a const pointer, but if I change to const Container& c then I can return a const pointer, but then the non-const case doesn't build.
Is there a way of defining this so that the const is interpreted as being part of the Container template parameter so that I only have to define one version of this function?
From the code it seems you have C++11 support in your compiler. Then you can probably use decltype and trailing return types as well:
template <class Container, class Pred>
auto getValuePtrIf(Container& c, Pred pred) -> decltype(&*std::begin(c))
{
auto it=std::find_if(std::begin(c), std::end(c), pred);
return (it!=std::end(c)) ? &(*it) : nullptr;
}
it will be of whatever type std::begin(c) gives you (iterator or const_iterator), so the type of &(*it) is the same as of decltype(&*std::begin(c)).
The simplest is to define both templates and let the compiler find the best match
template <class Container, class Pred>
typename const Container::value_type* getValuePtrIf(const Container& c, Pred pred)
{
auto it=std::find_if(c.begin(), c.end(), pred);
return (it!=c.end()) ? &(*it) : nullptr;
}
template <class Container, class Pred>
typename Container::value_type* getValuePtrIf(Container& c, Pred pred)
{
auto it=std::find_if(c.begin(), c.end(), pred);
return (it!=c.end()) ? &(*it) : nullptr;
}
If you object to duplicating code (a worth objection) due to maintenance issues you can try something like the following:
template <class Container, class Pred>
typename const Container::value_type* getValuePtrIf(const Container& c, Pred pred)
{
auto it=std::find_if(c.begin(), c.end(), pred);
return (it!=c.end()) ? &(*it) : nullptr;
}
template <class Container, class Pred>
typename Container::value_type* getValuePtrIf(Container& c, Pred pred)
{
return const_cast<Container::value_type*>(
getValuePtrIf(const_cast<const Container &>( c ), pred)
);
}
If it were me, I'd also replace Pred with const Pred & pred)
Robert Ramey

How can I write a custom algorithm that works on either a vector or map iterator

I want to write my own algorithm (just a function really) that takes a range of iterators. If the iterators are from a map, I want to use the data (iterator->second) value. If the iterator is "normal" like a vector or list, I just want to use the dereferenced iterator value.
I think, value-getter idea is right here, but you can implement it without c++11 and without structs at all, only using functions:
template <typename T>
const T& get(const T& t)
{
return t;
}
template <typename T, typename V>
const V& get(const std::pair<T,V>& t)
{
return t.second;
}
int main()
{
std::vector<int> v = {1};
std::cout << get(*v.begin());
std::cout << "\n----\n";
std::map<int, std::string> m;
m.insert(std::make_pair(0, "sss"));
std::cout << get(*m.cbegin());
}
You can make a value-getter class that extracts the value you're interested in. Note that this approach doesn't work if you store pairs in any container (it transforms all pairs, whether in a map or not). I'd think it would be a much clearer approach to only accept "regular" iterators and let it be callers job to transform map iterators appropriately (as suggested in the comments to your question.)
template<typename T>
struct get {
static auto val(const T& t) -> const T&
{
return t;
}
};
template<typename U, typename V>
struct get<std::pair<U, V>> {
static auto val(const std::pair<U, V>& p) -> const V&
{
return p.second;
}
};
// use like
get<decltype(*iter)>::val(*iter);
Convenience function could look like:
template<class T>
auto getval(const T& t) -> decltype(get<T>::val(t))
{
return get<T>::val(t);
}
You can overload the function based on the input:
void foo(const std::vector<int>::iterator& it1, const std::vector<int>::iterator& it2)
{
//use *it
}
void foo(const std::map<int,int>::iterator& it1, const std::map<int,int>::iterator& it2)
{
//use it->second
}
Edit:
I think this is the closest you can get to what you want to achieve:
template <typename T, typename X>
void foo(T const& x, X const& y)
{
}
template <typename T, typename S>
void foo(const typename std::map<T,S>::iterator& x, const typename std::map<T,S>::iterator& y)
{
}
int main()
{
std::map<int,int> x;
std::vector<int> y;
foo(x.begin(), x.end()); //will call second version
foo(y.begin(), y.end()); //will call first version
}
A trait should do the trick. First the type-deducing helper:
template <typename Iter>
typename iter_value<Iter>::value_type & iter_deref(Iter it)
{
return iter_value<Iter>::deref(it);
}
All we need is something like this:
template <typename Iter>
class iter_value
{
template <typename T> struct aux
{
typedef T type;
static type & deref(Iter it) { return *it; }
};
template <typename U, typename V> struct aux<std::pair<U const, V>>
{
typedef V type;
static type & deref(Iter it) { return it->second; }
};
typedef typename std::iterator_traits<Iter>::value_type type;
public:
typedef typename aux<type>::type value_type;
static value_type & deref(Iter it)
{
return aux<type>::deref(it);
}
};
You can create a function that extracts the value out of the iterator. Then you can overload that based on the type of the iterator. You can use that function in your algorithm. Assuming a vector of ints and a map of string->int, it could look like this:
int getValue(const std::vector<int>::iterator& it)
{
return *it;
}
int getValue(const std::map<std::string, int>::iterator& it)
{
return it->second;
}
Then the algorithm can use the function getValue() to get a value from the iterator.