The following does not compile:
#include <iostream>
int main()
{
int a{},b{},c{},d{};
for (auto& s : {a, b, c, d}) {
s = 1;
}
std::cout << a << std::endl;
return 0;
}
Try it on godbolt
Compiler error is: error: assignment of read-only reference 's'
Now in my actual case the list is made of member variables on a class.
Now, this doesn't work because the expression becomes an initializer_list<int> that actually copies a,b,c, and d - hence also not allowing modification.
My question is two-fold:
Is there any motivation behind not allowing to write a range-based for loop in this way ? eg. perhaps there could be a special case for naked brace expressions.
What is a syntactical neat way of fixing this type of loop ?
Something along this line would be preferred:
for (auto& s : something(a, b, c, d)) {
s = 1;
}
I do not consider pointer indirection a good solution (that is {&a, &b, &c, &d}) - any solution should give the element reference directly when the iterator is de-referenced.
Ranges are not as magic as people would like. In the end, there must be an object that the compiler can generate calls on to either a member function or free function begin() and end().
Closest you'll probably be able to come is:
#include <iostream>
int main()
{
int a{},b{},c{},d{};
for (auto s : {&a, &b, &c, &d} ) {
*s = 1;
}
std::cout << a << "\n";
return 0;
}
Just another solution within a wrapper idea:
template<typename T, std::size_t size>
class Ref_array {
using Array = std::array<T*, size>;
class Iterator {
public:
explicit Iterator(typename Array::iterator it) : it_(it) {}
void operator++() { ++it_; }
bool operator!=(const Iterator& other) const { return it_ != other.it_; }
decltype(auto) operator*() const { return **it_; }
private:
typename Array::iterator it_;
};
public:
explicit Ref_array(Array args) : args_(args) {}
auto begin() { return Iterator(args_.begin()); }
auto end() { return Iterator(args_.end()); }
private:
Array args_;
};
template<typename T, typename... Ts>
auto something(T& first, Ts&... rest) {
static_assert((std::is_same_v<T, Ts> && ...));
return Ref_array<T, 1 + sizeof...(Ts)>({&first, &rest...});
}
Then:
int main() {
int a{}, b{}, c{}, d{};
for (auto& s : something(a, b, c, d)) {
std::cout << s;
s = 1;
}
std::cout << std::endl;
for (auto& s : something(a, b, c, d))
std::cout << s;
}
outputs
0000
1111
According to the standard §11.6.4 List-initialization/p5 [dcl.init.list] [Emphasis Mine]:
An object of type 'std::initializer_list' is constructed from an
initializer list as if the implementation generated and materialized
(7.4) a prvalue of type “array of N const E”, where N is the number of
elements in the initializer list. Each element of that array is
copy-initialized with the corresponding element of the initializer
list, and the std::initializer_list object is constructed to refer
to that array. [ Note: A constructor or conversion function selected
for the copy shall be accessible (Clause 14) in the context of the
initializer list. — end note ] If a narrowing conversion is required
to initialize any of the elements, the program is ill-formed.
Thus, your compiler is complaining legitimately (i.e., auto &s deducts to int const& s and you cannot assign to s in the ranged for loop).
You could alleviate this problem by introducing a container instead of an initializer list (e.g., `std::vector’) with ‘std::reference_wrapper’:
#include <iostream>
#include <vector>
#include <functional>
int main()
{
int a{},b{},c{},d{};
for (auto& s : std::vector<std::reference_wrapper<int>>{a, b, c, d}) {
s.get()= 1;
}
std::cout << a << std::endl;
return 0;
}
Live Demo
To satisfy that syntax
for (auto& s : something{a, b, c, d}) {
s = 1;
}
you might create wrapper:
template <typename T>
struct MyRefWrapper
{
public:
MyRefWrapper(T& p) : p(&p) {}
T& operator =(const T& value) const { return *p = value; }
operator T& () const { return *p; }
private:
T* p;
};
Demo
Solution: use a reference wrapper
template <class It>
struct range_view_iterator : public It{//TODO: don't inherit It
auto& operator*() {
return (*this)->get();
}
};
template<class It>
range_view_iterator(It) -> range_view_iterator<It>;
template<class T>
struct range_view {
std::vector<std::reference_wrapper<T> > refs_;
range_view(std::initializer_list<std::reference_wrapper<T> > refs) : refs_{refs} {
}
auto begin() {
return range_view_iterator{ refs_.begin() };
}
auto end() {
return range_view_iterator{ refs_.end() };
}
};
Then used as:
for (auto& e : range_view<int>{a, b, c, d}) {
e = 1;
}
This doesn't try to answer the first question though.
You could create wrapper class for storing reference and which will have assignment operator to update this value:
template<class T>
struct Wrapper {
T& ref;
Wrapper(T& ref)
: ref(ref){}
template<class U>
void operator=(U u) {
ref = u;
}
};
template<class...T>
auto sth(T&...t) {
return std::array< Wrapper<std::common_type_t<T...> > ,sizeof...(t) >{Wrapper(t)...};
};
int main(){
int a{},b{},c{},d{};
for (auto s : sth(a,b,c,d)) {
s = 1;
}
std::cout << a << std::endl; // 1
Live demo
Related
I have some class Foo and a std::list<std::reference_wrapper<Foo>> and would like to iterate over its elements with a range-based for loop:
#include <list>
#include <functional>
#include <iostream>
class Foo {
public:
Foo(int a) : a(a) {}
int a;
};
int main() {
std::list<Foo> ls = {{1},{2},{3},{4}};
std::list<std::reference_wrapper<Foo>> refs(ls.begin(), std::next(ls.begin(),2));
for(auto &foo : refs) {
std::cout << foo.get().a << std::endl;
}
for(Foo &foo : refs) {
std::cout << foo.a << std::endl;
}
return 0;
}
Notice the additional get() when catching with auto, as we deduce type std::reference_wrapper<Foo>, whereas in the second case foo is already implicitly converted to type Foo& as we explicitly catch with this type.
I was actually looking for a way to catch with auto but implicitly cast away the std::reference_wrapper implicitly in order to not have to bother with the get() method all the time in the for body, so I tried introducing a fitting concept and catching with this, i.e. I tried
//this is not legal code
template<typename T>
concept LikeFoo = requires (T t) {
{ t.a };
};
int main() {
std::list<Foo> ls = {{1},{2},{3},{4}};
std::list<std::reference_wrapper<Foo>> refs(ls.begin(), std::next(ls.begin(),2));
for(LikeFoo auto &foo : refs) {
std::cout << foo.a << std::endl;
}
return 0;
}
and hoped that it would work. clang however deduces the type of foo to std::reference_wrapper<Foo>, so that in fact below code will be correct:
//this compiles with clang, but not with gcc
template<typename T>
concept LikeFoo = requires (T t) {
{ t.a };
};
int main() {
std::list<Foo> ls = {{1},{2},{3},{4}};
std::list<std::reference_wrapper<Foo>> refs(ls.begin(), std::next(ls.begin(),2));
for(LikeFoo auto &foo : refs) {
std::cout << foo.get().a << std::endl;
}
return 0;
}
However, gcc completely refuses to accept the range-based for loop and complains deduced initializer does not satisfy placeholder constraints, as it tries to check LikeFoo<std::reference_wrapper<Foo>>, which of course evaluates to false, so with gcc one cannot even catch foo concept-restricted. Two questions arise:
Which of the compilers is correct? Should LikeFoo auto& foo : refs be valid?
Is there a way to auto-catch (possibly concept-restricted) foo : refs such that one can avoid having to write get() in the for-loop body?
You can find this example at the Compiler explorer.
Which of the compilers is correct? Should LikeFoo auto& foo : refs be valid?
No. refs is a range of reference_wrapper<Foo>&, so foo deduces to a reference to reference_wrapper<Foo> - which does not have a member named a. A constrained variable declaration doesn't change how deduction works, it just effectively behaves like an extra static_assert.
Is there a way to auto-catch (possibly concept-restricted) foo : refs such that one can avoid having to write get() in the for-loop body?
Just by writing refs? No. But you can write a range adaptor to convert your range of reference_wrapper<T> to a range of T&. There is already such a thing in the standard library, transform:
for (auto &foo : refs | std::views::transform([](auto r) -> decltype(auto) { return r.get(); })) {
That's a mouthful, so we can make it its own named adaptor:
inline constexpr auto unwrap_ref = std::views::transform(
[]<typename T>(std::reference_wrapper<T> ref) -> T& { return ref; });
And then you can write either:
for (auto &foo : refs | unwrap_ref) { ... }
for (auto &foo : unwrap_ref(refs)) { ... }
Either way, foo here deduces to be a Foo.
With a little bit more work, you can write a range adaptor that unwraps reference_wrapper<T> but preserves any other reference type.
Here is a bare minimum working example for a wrapper that calls get when being dereferenced.
#include <list>
#include <functional>
#include <iostream>
template <typename T>
struct reference_wrapper_unpacker {
struct iterator {
typename T::iterator it;
iterator& operator++() {
it++;
return *this;
}
iterator& operator--() {
it--;
return *this;
}
typename T::value_type::type& operator*() {
return it->get();
}
bool operator!=(const iterator& other) const {
return it != other.it;
}
};
reference_wrapper_unpacker(T& container) : t(container) {}
T& t;
iterator begin() const {
return {t.begin()};
}
iterator end() const {
return {t.end()};
}
};
class Foo {
public:
Foo(int a) : a(a) {}
int a;
};
int main() {
std::list<Foo> ls = {{1},{2},{3},{4}};
std::list<std::reference_wrapper<Foo>> refs(ls.begin(), std::next(ls.begin(),2));
for(auto &foo : refs) {
std::cout << foo.get().a << std::endl;
}
for(Foo &foo : refs) {
std::cout << foo.a << std::endl;
}
for(auto &foo : reference_wrapper_unpacker{refs}) {
std::cout << foo.a << std::endl;
}
return 0;
}
To make it usable in generic code you would need to SFINAE to detect if the container actually has a reference_wrapper, and if not, just return the original container.
I'll leave that part out since it was not a part of the original question.
Say I have a struct:
struct Boundary {
int top;
int left;
int bottom;
int right;
}
and a vector
std::vector<Boundary> boundaries;
What would be the most C++ style way to access the structs to get the sum of top, left, bottom and right separately?
I could write a loop like
for (auto boundary: boundaries) {
sum_top+=boundary.top;
sum_bottom+=boundary.bottom;
...
}
This seems like a lot of repetition. Of course I could do this instead:
std::vector<std::vector<int>> boundaries;
for (auto boundary: boundaries) {
for(size_t i=0; i<boundary.size();i++) {
sums.at(i)+=boundary.at(i)
}
}
But then I'd loose all the meaningful struct member names. Is there a way so that I can write a something like the following function:
sum_top=make_sum(boundaries,"top");
Reflection does not seem to be an option in C++. I am open to use C++ up to Version 14.
std::accumulate(boundaries.begin(), boundaries.end(), 0,
[](Boundary const & a, Boundary const & b) { return a.top + b.top); });
(IIRC the Boundary const &'s can be auto'd in C++17)
This doesn't make it generic for the particular element, which - indeed, due to the lack of reflection - isn't easy to generalize.
There are a few ways to ease your pain, though;
You could use a pointer-to-member, which is fine for your szenario but not very c-plusplus-y:
int Sum(vector<Boundary>const & v, int Boundary::*pMember)
{
return std::accumulate( /*...*/,
[&](Boundary const & a, Boundary const & b)
{
return a.*pMember + b.*pMember;
});
}
int topSum = Sum(boundaries, &Boundary::top);
(For pointer-to-member, see e.g. here: Pointer to class data member "::*")
You could also make this generic (any container, any member type), and you could also replace the pointer-to-member with a lambda (also allowing member functions)
You can achieve the desired effect with Boost Hana reflection:
#include <iostream>
#include <vector>
#include <boost/hana.hpp>
struct Boundary {
BOOST_HANA_DEFINE_STRUCT(Boundary,
(int, top),
(int, left),
(int, bottom),
(int, right)
);
};
template<class C, class Name>
int make_sum(C const& c, Name name) {
int sum = 0;
for(auto const& elem : c) {
auto& member = boost::hana::at_key(elem, name);
sum += member;
}
return sum;
}
int main() {
std::vector<Boundary> v{{0,0,1,1}, {1,1,2,2}};
std::cout << make_sum(v, BOOST_HANA_STRING("top")) << '\n';
std::cout << make_sum(v, BOOST_HANA_STRING("bottom")) << '\n';
}
See Introspecting user-defined types for more details.
I am probably a bit late to the party, but I wanted to add answer inspired by the one of #TobiasRibizel. Instead of adding much boilerplate code to your struct we add more boilerplate code once in the form of an iterator over (specified) members of a struct.
#include <iostream>
#include <string>
#include <map>
template<class C, typename T, T C::* ...members>
class struct_it {
public:
using difference_type = std::ptrdiff_t;
using value_type = T;
using pointer = T*;
using reference = T&;
using iterator_category = std::bidirectional_iterator_tag;
constexpr struct_it (C &c) : _index{0}, _c(c)
{}
constexpr struct_it (size_t index, C &c) : _index{index}, _c(c)
{}
constexpr static struct_it make_end(C &c) {
return struct_it(sizeof...(members), c);
}
constexpr bool operator==(const struct_it& other) const {
return other._index == _index; // Does not check for other._c == _c, since that is not always possible. Maybe do &other._c == &_c?
}
constexpr bool operator!=(const struct_it& other) const {
return !(other == *this);
}
constexpr T& operator*() const {
return _c.*_members[_index];
}
constexpr T* operator->() const {
return &(_c.*_members[_index]);
}
constexpr struct_it& operator--() {
--_index;
return *this;
}
constexpr struct_it& operator--(int) {
auto copy = *this;
--_index;
return copy;
}
constexpr struct_it& operator++() {
++_index;
return *this;
}
constexpr struct_it& operator++(int) {
auto copy = *this;
++_index;
return copy;
}
private:
size_t _index;
C &_c;
std::array<T C::*, sizeof...(members)> _members = {members...}; // Make constexpr static on C++17
};
template<class C, typename T, T C::* ...members>
using cstruct_it = struct_it<const C, T, members...>;
struct boundary {
int top;
int bottom;
int left;
int right;
using iter = struct_it<boundary, int, &boundary::top, &boundary::bottom, &boundary::left, &boundary::right>;
using citer = cstruct_it<boundary, int, &boundary::top, &boundary::bottom, &boundary::left, &boundary::right>;
iter begin() {
return iter{*this};
}
iter end() {
return iter::make_end(*this);
}
citer cbegin() const {
return citer{*this};
}
citer cend() const {
return citer::make_end(*this);
}
};
int main() {
boundary b{1,2,3,4};
for(auto i: b) {
std::cout << i << ' '; // Prints 1 2 3 4
}
std::cout << '\n';
}
It works on C++14, on C++11 the constexpr functions are all const by default so they don't work, but just getting rid of the constexpr should do the trick. The nice thing is that you can choose just some members of your struct and iterate over them. If you have the same few members that you will always iterate over, you can just add a using. That is why I chose to make the pointer-to-members part of the template, even if it is actually not necessary, since I think that only the iterators over the same members should be of the same type.
One could also leave that be, replace the std::array by an std::vector and choose at runtime over which members to iterate.
Without going too much into the memory layout of C++ objects, I would propose replacing the members by 'reference-getters', which adds some boilerplate code to the struct, but except for replacing top by top() doesn't require any changes in the way you use the struct members.
struct Boundary {
std::array<int, 4> coordinates;
int& top() { return coordinates[0]; }
const int& top() const { return coordinates[0]; }
// ...
}
Boundary sum{};
for (auto b : boundaries) {
for (auto i = 0; i < 4; ++i) {
sum.coordinates[i] += b.coordinates[i];
}
}
I've got this Map in my Entity-Component-System:
std::map<u_int32_t, std::vector<std::shared_ptr<Component>>> _componentMap;
The u_int32_t is the key to a vector of components. There can be multiple instances of the same component. (That's why there's a vector).
Now I would like to have a templated getter-function that returns a Vector of an inherited type:
template<class T> inline const std::vector<std::shared_ptr<T>> & getVector() const
{
u_int32_t key = getKey<T>();
return static_cast<std::vector<std::shared_ptr<T>>>(_componentMap.count(key) ? _componentMap.at(key) : _emptyComponentVec);
}
I know that this doesn't work, since std::vectors of different types are completely unrelated and I cannot cast between them. I would also like to avoid allocating a new vector every time this function is called.
But how I can I get the desired behaviour? When the the components are added I can create an std::vector of the desired derived type.
The question could also be: How can I have an std::map containing different types of std::vector?
For any solutions I can not link against boost, though if absolutely needed, I could integrate single headers of boost.
template<class It>
struct range_view {
It b, e;
It begin() const { return b; }
It end() const { return e; }
using reference = decltype(*std::declval<It const&>());
reference operator[](std::size_t n) const
{
return b[n];
}
bool empty() const { return begin()==end(); }
std::size_t size() const { return end()-begin(); }
reference front() const {
return *begin();
}
reference back() const {
return *std::prev(end());
}
template<class O>
range_view( O&& o ):
b(std::begin(o)), e(std::end(o))
{}
};
this is a quick range view. It can be improved.
Now all you need to do is write a pseudo-random-access iterator that converts its arguments. So it takes a random access iterator over a type T, then does some operation F to return a type U. It forwards all other operations.
The map then stores std::vector<std::shared_ptr<Base>>. The gettor returns a range_view< converting_iterator<spBase2spDerived> >.
Here is a crude implementation of a solution I have in mind for this problem. Of course, there are many rooms to refine the code, but hopefully it conveys my idea.
#include <iostream>
#include <map>
#include <vector>
#include <memory>
using namespace std;
class Base {
public:
virtual void f() const = 0;
};
class A : public Base {
public:
static const int type = 0;
explicit A(int a) : a_(a) {}
void f() const { cout << "calling A::f" << endl;}
int a_;
};
class B : public Base {
public:
static const int type = 1;
explicit B(int a) : a_(a) {}
void f() const { cout << "calling B::f" << endl;}
int a_;
};
class MapWrapper {
public:
template<class T>
void append(int a, vector<T> const& vec) {
types_[a] = T::type;
my_map_[a] = make_shared<vector<T>>(vec);
}
template<class T>
vector<T> const& get(int a) const {
return *static_pointer_cast<vector<T>>( my_map_.at(a) );
}
map<int, shared_ptr<void>> const& get_my_map() const {
return my_map_;
}
vector<shared_ptr<Base>> get_base(int a) const {
vector<shared_ptr<Base>> ret;
switch(types_.at(a)) {
case 0: {
auto const vec = get<A>(a);
for(auto v : vec)
ret.push_back(make_shared<A>(v));
break;
}
case 1: {
auto const vec = get<B>(a);
for(auto v : vec)
ret.push_back(make_shared<B>(v));
break;
}
}
return ret;
}
map<int, shared_ptr<void>> my_map_;
map<int, int> types_;
};
int main() {
MapWrapper map_wrapper;
map_wrapper.append(10, vector<A>{A(2), A(4)});
map_wrapper.append(20, vector<B>{B(5), B(7), B(9)});
for(auto const& w : map_wrapper.get_my_map())
for(auto v : map_wrapper.get_base(w.first))
v->f();
for(auto const& x: map_wrapper.get<A>(10))
cout << x.a_ << " ";
cout << endl;
for(auto const& x: map_wrapper.get<B>(20))
cout << x.a_ << " ";
return 0;
}
The solution was to use reinterpret_cast:
template<class T> inline std::vector<std::shared_ptr<T>> * getVector() const
{
auto key = getKey<T>();
return reinterpret_cast<std::vector<std::shared_ptr<T>> *>( (_componentMap.count(key) ? _componentMap.at(key).get() : const_cast<std::vector<std::shared_ptr<Component>> *>(&_emptyComponentSharedPtrVec)) );
}
It's not very pretty but it does work fine and it fulfills all requirements.
This question already has answers here:
How to make my custom type to work with "range-based for loops"?
(10 answers)
Closed 7 years ago.
I have a class like this:
class Foo {
private:
int a,b,c,d;
char bar;
double m,n
public:
//constructors here
};
I wanna allow range-for loop on my class, e.g.
Foo foo {/*...*/};
for(auto& f : foo) {
//f will be a specific order such as c,b,d,(int)m,(int)bar,a,(int)n
}
How can I achieve this? I was looking at iterator but don't know what are the requirements for a range-for loop. (Please don't ask me to use array or STL type)
The loop is defined to be equivalent to:
for ( auto __begin = <begin-expr>,
__end = <end-expr>;
__begin != __end;
++__begin ) {
auto& f = *__begin;
// loop body
}
where <begin-expr> is foo.begin(), or begin(foo) if there isn't a suitable member function, and likewise for <end-expr>. (This is a simplification of the specification in C++11 6.5.4, for this particular case where the range is a lvalue of class type).
So you need to define an iterator type that supports pre-increment ++it, dereference *it and comparison i1 != i2; and either
give foo public member functions begin() and end(); or
define non-member functions begin(foo) and end(foo), in the same namespace as foo so that they can be found by argument-dependent lookup.
This seems fairly un-C++-like, and rather prone to breakage. What if the iteration order is changed (accidentally or not) during some update in the future? Clients relying on a specific order will break.
All that said if you wish to support this all you have to do is implement your own iterator and provide begin/end methods (or free functions with those names) to provide access. Then the iterator takes care of remembering which attribute it's currently looking at and provides it when dereferenced.
Here is a basic framework I came up with:
#include <iterator>
struct Foo;
template<typename Type>
struct MemberPtrBase {
virtual ~MemberPtrBase() { }
virtual Type get() const = 0;
virtual MemberPtrBase & set(Type const &) = 0;
};
template<typename Class, typename RealType, typename CommonType>
struct MemberPtr : MemberPtrBase<CommonType> {
public:
MemberPtr(Class * object, RealType(Class::*member))
: m_object(object), m_ptr(member)
{ }
CommonType get() const {
return m_object->*m_ptr;
}
MemberPtr & set(CommonType const & val) {
m_object->*m_ptr = val;
return *this;
}
MemberPtr & operator=(RealType const & val) {
return set(val);
}
operator CommonType() const {
return get();
}
private:
Class * m_object;
RealType (Class::*m_ptr);
};
template<typename Class, typename... Types>
struct MemberIterator {
public:
using CommonType = typename std::common_type<Types...>::type;
public:
MemberIterator(Class & obj, std::size_t idx, Types(Class::*...member))
: m_object(obj), m_index(idx), m_members { new MemberPtr<Class, Types, CommonType>(&obj, member)... }
{ }
MemberPtrBase<CommonType> & operator*() const {
return *m_members[m_index];
}
bool operator==(MemberIterator const & it) const {
return (&m_object == &it.m_object) && (m_index == it.m_index);
}
bool operator!=(MemberIterator const & it) const {
return (&m_object != &it.m_object) || (m_index != it.m_index);
}
MemberIterator & operator++() {
++m_index;
return *this;
}
private:
Class & m_object;
std::size_t m_index;
MemberPtrBase<CommonType> * m_members[sizeof...(Types)];
};
struct Foo {
public:
using iterator = MemberIterator<Foo, int, int, int, int>;
public:
Foo(int a, int b, int c, int d)
: m_a(a), m_b(b), m_c(c), m_d(d)
{ }
iterator begin() {
return iterator(*this, 0, &Foo::m_b, &Foo::m_d, &Foo::m_c, &Foo::m_a);
}
iterator end() {
return iterator(*this, 4, &Foo::m_b, &Foo::m_d, &Foo::m_c, &Foo::m_a);
}
private:
int m_a, m_b, m_c, m_d;
};
If you have a basic understanding of variadic templates, I think the code is self-explanatory.
Usage is simple:
#include <iostream>
int main(int argc, char ** argv) {
Foo foo { 1, 2, 3, 4 };
for(auto & mem : foo) {
std::cout << mem.get() << std::endl;
mem.set(3);
}
for(auto & mem : foo) {
std::cout << mem.get() << std::endl;
}
}
A POC can be found on ideone
Given the following:
struct Foo
{
int bar() const;
};
struct IsEqual : public std::unary_function<Foo*, bool>
{
int val;
IsEqual(int v) : val(v) {}
bool operator()(const Foo* elem) const
{
return elem->bar() == val;
}
};
I have a container of Foo* and I use std::find_if and std::not1 to find out if there are any elements in the container where bar() returns something different from a given value. The code looks like this:
// Are all elements equal to '2'?
bool isAllEqual(const std::vector<Foo*> &vec)
{
return find_if(vec.begin(), vec.end(), std::not1(IsEqual(2))) == vec.end();
}
Fast-forward into the future and I now have a different container, this time containing std::tr1::shared_ptr<Foo>. I'd love to simply re-use my functor in an overloaded version of isAllEqual(). But I can't. Foo* and shared_ptr<Foo> are different types. And I need to inherit from unary_function so I can use not1. It'd be more elegant if I could avoid writing the same functor twice.
Questions:
Is there any way to write IsEqual so it can use both raw and smart pointers?
Did I handcuff myself by using std::not1? Should I just write IsNotEqual instead?
Restrictions:
I can't use anything from the boost library.
Our compiler isn't cool enough to support C++0x lambdas.
How about:
template<typename T>
struct IsEqual : public std::unary_function<const T&, bool>
{
int val;
IsEqual(int v) : val(v) {}
bool operator()(const T& elem) const
{
return elem->bar() == val;
}
};
template<typename T>
IsEqual<T> DeduceEqualityComparer(int v, T) { return IsEqual<T>(v); }
// Are all elements equal to '2'?
template<typename TContainer>
bool isAllEqual(const TContainer& coll)
{
using std::begin; // in C++0x, or else write this really simple function yourself
using std::end;
if (begin(coll) == end(coll)) return true;
return find_if(begin(coll), end(coll), std::not1(DeduceEqualityComparer(2, *begin(coll)))) == end(coll);
}
// --*-- C++ --*--
#include <vector>
#include <algorithm>
#include <iostream>
// Template unary function example.
template <typename T>
struct IsEqual : public std::unary_function<T, bool>
{
int v;
IsEqual (int v) : v (v) {}
bool operator () (const T & elem) const
{
return elem ? elem->bar () == v : false;
}
};
// Generic algorithm implementation example...
template <typename T1, typename T2>
bool isAllEqual (const T1 & c, T2 v)
{
return find_if (
c.begin (), c.end (),
std::not1 (IsEqual <typename T1::value_type> (v))) == c.end ();
}
// Some arbitrary pointer wrapper implementation,
// provided just for an example, not to include any
// specific smart pointer implementation.
template <typename T>
class WrappedPtr
{
const T *v;
public:
typedef void (WrappedPtr<T>::*unspecified_boolean_type) () const;
WrappedPtr (const T *v) : v (v) {}
const T *operator -> () const { return v; }
operator unspecified_boolean_type () const
{
return v != NULL ?
&WrappedPtr<T>::unspecified_boolean_true : NULL;
}
private:
void unspecified_boolean_true () const {}
};
// Example of structure that could be used with our algorithm.
struct Foo
{
int v;
Foo (int v) : v (v) {}
int bar () const
{
return v;
}
};
// Usage examples...
int main ()
{
Foo f1 (2), f2 (2);
// Example of using raw pointers...
{
std::vector<Foo *> vec;
vec.push_back (NULL);
vec.push_back (&f1);
vec.push_back (&f2);
if (isAllEqual (vec, 2))
std::cout << "All equal to 2" << std::endl;
else
std::cout << "Not all equal to 2" << std::endl;
}
// Example of using smart pointers...
{
std::vector< WrappedPtr<Foo> > vec;
vec.push_back (NULL);
vec.push_back (&f1);
vec.push_back (&f2);
if (isAllEqual (vec, 2))
std::cout << "All equal to 2" << std::endl;
else
std::cout << "Not all equal to 2" << std::endl;
}
}
My shot would be something like this:
template<typename PtrToFoo>
struct IsEqual : public std::unary_function<PtrToFoo, bool>
{
int val;
IsEqual(int v) : val(v) {}
bool operator()(PtrToFoo elem) const
{
return elem->bar() == val;
}
};
You'll have a different operator() instantiation for everything dereferencable with ->, so raw pointers and smart pointers.
You could maybe do something tricky with implicit conversions:
class IsEqualArg {
public:
// Implicit conversion constructors!
IsEqualArg(Foo* foo) : ptr(foo) {}
IsEqualArg(const std::tr1::shared_ptr<Foo>& foo) : ptr(&*foo) {}
private:
Foo* ptr;
friend struct IsEqual;
};
struct IsEqualArg : public std::unary_function<IsEqualArg, bool> {
bool operator()( const IsEqualArg& arg ) const;
//...
};
But I'd really rather just write a IsNotEqual.
Ben's answer is really the only thing you can do in c++03. In C++0x though, and/or with boost::bind, you don't need to inherit from unary_function. This allows you to use a templated () operator. You can usually get away with the same in C++03 but I think that it's technically incorrect to do so.