Related
I have a function that takes a vector-like input. To simplify things, let's use this print_in_order function:
#include <iostream>
#include <vector>
template <typename vectorlike>
void print_in_order(std::vector<int> const & order,
vectorlike const & printme) {
for (int i : order)
std::cout << printme[i] << std::endl;
}
int main() {
std::vector<int> printme = {100, 200, 300};
std::vector<int> order = {2,0,1};
print_in_order(order, printme);
}
Now I have a vector<Elem> and want to print a single integer member, Elem.a, for each Elem in the vector. I could do this by creating a new vector<int> (copying a for all Elems) and pass this to the print function - however, I feel like there must be a way to pass a "virtual" vector that, when operator[] is used on it, returns this only the member a. Note that I don't want to change the print_in_order function to access the member, it should remain general.
Is this possible, maybe with a lambda expression?
Full code below.
#include <iostream>
#include <vector>
struct Elem {
int a,b;
Elem(int a, int b) : a(a),b(b) {}
};
template <typename vectorlike>
void print_in_order(std::vector<int> const & order,
vectorlike const & printme) {
for (int i : order)
std::cout << printme[i] << std::endl;
}
int main() {
std::vector<Elem> printme = {Elem(1,100), Elem(2,200), Elem(3,300)};
std::vector<int> order = {2,0,1};
// how to do this?
virtual_vector X(printme) // behaves like a std::vector<Elem.a>
print_in_order(order, X);
}
It's not really possible to directly do what you want. Instead you might want to take a hint from the standard algorithm library, for example std::for_each where you take an extra argument that is a function-like object that you call for each element. Then you could easily pass a lambda function that prints only the wanted element.
Perhaps something like
template<typename vectorlike, typename functionlike>
void print_in_order(std::vector<int> const & order,
vectorlike const & printme,
functionlike func) {
for (int i : order)
func(printme[i]);
}
Then call it like
print_in_order(order, printme, [](Elem const& elem) {
std::cout << elem.a;
});
Since C++ have function overloading you can still keep the old print_in_order function for plain vectors.
Using member pointers you can implement a proxy type that will allow you view a container of objects by substituting each object by one of it's members (see pointer to data member) or by one of it's getters (see pointer to member function). The first solution addresses only data members, the second accounts for both.
The container will necessarily need to know which container to use and which member to map, which will be provided at construction. The type of a pointer to member depends on the type of that member so it will have to be considered as an additional template argument.
template<class Container, class MemberPtr>
class virtual_vector
{
public:
virtual_vector(const Container & p_container, MemberPtr p_member_ptr) :
m_container(&p_container),
m_member(p_member_ptr)
{}
private:
const Container * m_container;
MemberPtr m_member;
};
Next, implement the operator[] operator, since you mentioned that it's how you wanted to access your elements. The syntax for dereferencing a member pointer can be surprising at first.
template<class Container, class MemberPtr>
class virtual_vector
{
public:
virtual_vector(const Container & p_container, MemberPtr p_member_ptr) :
m_container(&p_container),
m_member(p_member_ptr)
{}
// Dispatch to the right get method
auto operator[](const size_t p_index) const
{
return (*m_container)[p_index].*m_member;
}
private:
const Container * m_container;
MemberPtr m_member;
};
To use this implementation, you would write something like this :
int main() {
std::vector<Elem> printme = { Elem(1,100), Elem(2,200), Elem(3,300) };
std::vector<int> order = { 2,0,1 };
virtual_vector<decltype(printme), decltype(&Elem::a)> X(printme, &Elem::a);
print_in_order(order, X);
}
This is a bit cumbersome since there is no template argument deduction happening. So lets add a free function to deduce the template arguments.
template<class Container, class MemberPtr>
virtual_vector<Container, MemberPtr>
make_virtual_vector(const Container & p_container, MemberPtr p_member_ptr)
{
return{ p_container, p_member_ptr };
}
The usage becomes :
int main() {
std::vector<Elem> printme = { Elem(1,100), Elem(2,200), Elem(3,300) };
std::vector<int> order = { 2,0,1 };
auto X = make_virtual_vector(printme, &Elem::a);
print_in_order(order, X);
}
If you want to support member functions, it's a little bit more complicated. First, the syntax to dereference a data member pointer is slightly different from calling a function member pointer. You have to implement two versions of the operator[] and enable the correct one based on the member pointer type. Luckily the standard provides std::enable_if and std::is_member_function_pointer (both in the <type_trait> header) which allow us to do just that. The member function pointer requires you to specify the arguments to pass to the function (non in this case) and an extra set of parentheses around the expression that would evaluate to the function to call (everything before the list of arguments).
template<class Container, class MemberPtr>
class virtual_vector
{
public:
virtual_vector(const Container & p_container, MemberPtr p_member_ptr) :
m_container(&p_container),
m_member(p_member_ptr)
{}
// For mapping to a method
template<class T = MemberPtr>
auto operator[](std::enable_if_t<std::is_member_function_pointer<T>::value == true, const size_t> p_index) const
{
return ((*m_container)[p_index].*m_member)();
}
// For mapping to a member
template<class T = MemberPtr>
auto operator[](std::enable_if_t<std::is_member_function_pointer<T>::value == false, const size_t> p_index) const
{
return (*m_container)[p_index].*m_member;
}
private:
const Container * m_container;
MemberPtr m_member;
};
To test this, I've added a getter to the Elem class, for illustrative purposes.
struct Elem {
int a, b;
int foo() const { return a; }
Elem(int a, int b) : a(a), b(b) {}
};
And here is how it would be used :
int main() {
std::vector<Elem> printme = { Elem(1,100), Elem(2,200), Elem(3,300) };
std::vector<int> order = { 2,0,1 };
{ // print member
auto X = make_virtual_vector(printme, &Elem::a);
print_in_order(order, X);
}
{ // print method
auto X = make_virtual_vector(printme, &Elem::foo);
print_in_order(order, X);
}
}
You've got a choice of two data structures
struct Employee
{
std::string name;
double salary;
long payrollid;
};
std::vector<Employee> employees;
Or alternatively
struct Employees
{
std::vector<std::string> names;
std::vector<double> salaries;
std::vector<long> payrollids;
};
C++ is designed with the first option as the default. Other languages such as Javascript tend to encourage the second option.
If you want to find mean salary, option 2 is more convenient. If you want to sort the employees by salary, option 1 is easier to work with.
However you can use lamdas to partially interconvert between the two. The lambda is a trivial little function which takes an Employee and returns a salary for him - so effectively providing a flat vector of doubles we can take the mean of - or takes an index and an Employees and returns an employee, doing a little bit of trivial data reformatting.
template<class F>
struct index_fake_t{
F f;
decltype(auto) operator[](std::size_t i)const{
return f(i);
}
};
template<class F>
index_fake_t<F> index_fake( F f ){
return{std::move(f)};
}
template<class F>
auto reindexer(F f){
return [f=std::move(f)](auto&& v)mutable{
return index_fake([f=std::move(f),&v](auto i)->decltype(auto){
return v[f(i)];
});
};
}
template<class F>
auto indexer_mapper(F f){
return [f=std::move(f)](auto&& v)mutable{
return index_fake([f=std::move(f),&v](auto i)->decltype(auto){
return f(v[i]);
});
};
}
Now, print in order can be rewritten as:
template <typename vectorlike>
void print(vectorlike const & printme) {
for (auto&& x:printme)
std::cout << x << std::endl;
}
template <typename vectorlike>
void print_in_order(std::vector<int> const& reorder, vectorlike const & printme) {
print(reindexer([&](auto i){return reorder[i];})(printme));
}
and printing .a as:
print_in_order( reorder, indexer_mapper([](auto&&x){return x.a;})(printme) );
there may be some typos.
It is possible to write a method which can return reference or copy (getMember(bool getCopy)) to class member based on bool argument passed to this method?
class Class
{
const std::vector<int>& getMember() { return _member; }
const std::vector<int> getCopyOfMember() { return _member; }
??? getMember(bool getCopy) { ??? }
std::vector<int> _member;
}
I can use:
Class cl;
const std::vector<int>& myVector = isCopyNeeded ?
cl.getCopyMember() :
cl.getMember();
for (auto elem : myVector)
...
Hovewer I want something like this:
for (auto elem : cl.getMember(isCopyNeeded))
...
A function can only have one return type, so no, it can't be done.
It's also not clear what purpose it coud possibly serve.
Normally, you would provide the function that returns a const reference:
const std::vector<int>& getMember() const { return _member; }
and then your users can choose if they want a reference:
const std::vector<int>& aReference = anObject.getMember();
or a copy:
std::vector<int> aCopy = anObject.getMember();
You cannot change the return type based on the value of an argument. One option is to use two overloaded functions using tag types to differentiate them.
const std::vector<int>& getMember(std::true_type tag) { return _member; }
std::vector<int> getMember(std::false_type tag) { return _member; }
You need to add
#include <type_traits>
to use std::true_type and std::false_type.
Of course, you have to call them using a std::true_type or std::false_type as arguments.
Class c;
auto ret1 = c.getNumber(std:::true_type{});
auto ret2 = c.getNumber(std:::false_type{});
In general, templates arguments can be abstract classes, as the program below also shows. But it seems that the compare functor in sort must not be abstract. At least the following does not compile with VC++ 11 and on Oracle Studio 12.
#include <vector>
#include <algorithm>
class Functor
{
public:
virtual bool operator()(int a, int b) const = 0;
};
class MyFunctor: public Functor
{
public:
virtual bool operator()(int a, int b) const { return true; }
};
int _tmain(int argc, _TCHAR* argv[])
{
vector<Functor> fv; // template of abstract class is possible
vector<int> v;
MyFunctor* mf = new MyFunctor();
sort(v.begin(), v.end(), *mf);
Functor* f = new MyFunctor();
// following line does not compile:
// "Cannot have a parameter of the abstract class Functor"
sort(v.begin(), v.end(), *f);
return 0;
}
Now, I wonder whether this is a general property of functor arguments, or does it depend on the STL implementation? Is there a way to get, what I wanted to do?
Functors generally need to be copyable. Polymorphic base classes are generally not copyable, and abstract bases never.
Update: Thanks to the comments by #ahenderson and #ltjax, here's a very simple way to produce a wrapper object that holds your original, polymorphic reference:
#include <functional>
std::sort(v.begin(), v.end(), std::ref(*f));
// ^^^^^^^^^^^^
The result of std::ref is a std::refrence_wrapper which is exactly what you need: A class with value semantics that holds a reference to your original object.
The fact that functors get copied throws off lots of people who want to accumulate something inside the functor and then wonder why the results are off. The functor should really take a reference to an external object. To wit:
Bad! Won't work as you expect; the functor may get copied arbitrarily:
struct Func1 {
int i;
Func1() : i(0) { }
void operator()(T const & x) { /* ... */ }
};
Func1 f;
MyAlgo(myContainer, f);
Good: You provide the accumulator; it's safe to copy the functor:
struct Func2 {
int & i;
Func2(int & n) : i(n) { }
void operator()(T const & x) { /* ... */ }
};
int result;
MyAlgo(myContainer, Func2(result));
As Kerrek has said you can't do it directly:
But one level of indirection and you're OK.
struct AbstractFunctor
{
AbstractFunctor( Functor * in_f ): f(in_f) {}
// TODO: Copy constructor etc.
Functor * f;
bool operator()(int a, int b) const { return (*f)(a,b); }
};
int main()
{
vector<int> v;
Functor * mf = new MyFunctor();
sort(v.begin(), v.end(), AbstractFunctor(mf) );
}
As Kerrek and Michael Anderson said, you can't do it directly. As Michael shows, you can write a wrapper class. But there's also one in std:: :
sort(v.begin(),
v.end(),
std::bind(&Functor::operator(),
mf,
std::placeholders::_1,
std::placeholders::_2) );
This might sound like a stupid problem but I wondered for a long time is there a better way that this:
struct X
{
int a;
int b;
};
bool sortComp(const X first, const X second)
{
if (first.a!=second.a)
return (first.a<second.a);
else
return (first.b<second.b);
}
class setComp
{
public:
bool operator() (const X first, const X second) const
{
if (first.a!=second.a)
return (first.a<second.a);
else
return (first.b<second.b);
}
};
int main()
{
vector<X> v;
set<X, setComp> s;
sort(begin(v), end(v),sortComp);
}
As you see I implement the same functionality twice, once for sorting, and once for implicit sorting in the set. Is there a way to avoid code duplication?
Sure, just choose one of both and change the call of the other.
// choosing the function object
sort(begin(v), end(v), setComp()); // create setComp, sort will call operator()
// choosing the function
set<X, bool(*)(const X, const X)> s(sortComp); // pass function pointer
I personally would recommend the functor version.
trying to compile the following code I get this compile error, what can I do?
ISO C++ forbids taking the address of
an unqualified or parenthesized
non-static member function to form a
pointer to member function.
class MyClass {
int * arr;
// other member variables
MyClass() { arr = new int[someSize]; }
doCompare( const int & i1, const int & i2 ) { // use some member variables }
doSort() { std::sort(arr,arr+someSize, &doCompare); }
};
doCompare must be static. If doCompare needs data from MyClass you could turn MyClass into a comparison functor by changing:
doCompare( const int & i1, const int & i2 ) { // use some member variables }
into
bool operator () ( const int & i1, const int & i2 ) { // use some member variables }
and calling:
doSort() { std::sort(arr, arr+someSize, *this); }
Also, isn't doSort missing a return value?
I think it should be possible to use std::mem_fun and some sort of binding to turn the member function into a free function, but the exact syntax evades me at the moment.
EDIT: Doh, std::sort takes the function by value which may be a problem. To get around this wrap the function inside the class:
class MyClass {
struct Less {
Less(const MyClass& c) : myClass(c) {}
bool operator () ( const int & i1, const int & i2 ) {// use 'myClass'}
MyClass& myClass;
};
doSort() { std::sort(arr, arr+someSize, Less(*this)); }
}
As Andreas Brinck says, doCompare must be static (+1). If you HAVE TO have a state in your comparator function (using the other members of the class) then you'd better use a functor instead of a function (and that will be faster):
class MyClass{
// ...
struct doCompare
{
doCompare( const MyClass& info ) : m_info(info) { } // only if you really need the object state
const MyClass& m_info;
bool operator()( const int & i1, const int & i2 )
{
// comparison code using m_info
}
};
doSort()
{ std::sort( arr, arr+someSize, doCompare(*this) ); }
};
Using a functor is always better, just longer to type (that can be unconvenient but oh well...)
I think you can also use std::bind with the member function but I'm not sure how and that wouldn't be easy to read anyway.
UPDATE 2014: Today we have access to c++11 compilers so you could use a lambda instead, the code would be shorter but have the exact same semantic.
The solution proposed by Rob is now valid C++11 (no need for Boost):
void doSort()
{
using namespace std::placeholders;
std::sort(arr, arr+someSize, std::bind(&MyClass::doCompare, this, _1, _2));
}
Indeed, as mentioned by Klaim, lambdas are an option, a bit more verbose (you have to "repeat" that the arguments are ints):
void doSort()
{
std::sort(arr, arr+someSize, [this](int l, int r) {return doCompare(l, r); });
}
C++14 supports auto here:
void doSort()
{
std::sort(arr, arr+someSize, [this](auto l, auto r) {return doCompare(l, r); });
}
but still, you declared that arguments are passed by copy.
Then the question is "which one is the most efficient". That question was treated by Travis Gockel: Lambda vs Bind. His benchmark program gives on my computer (OS X i7)
Clang 3.5 GCC 4.9
lambda 1001 7000
bind 3716166405 2530142000
bound lambda 2438421993 1700834000
boost bind 2925777511 2529615000
boost bound lambda 2420710412 1683458000
where lambda is a lambda used directly, and lambda bound is a lambda stored in a std::function.
So it appears that lambdas are a better option, which is not too much of a surprise since the compiler is provided with higher level information from which it can make profit.
You can use boost::bind:
void doSort() {
std::sort(arr,arr+someSize, boost::bind(&MyClass::doCompare, this, _1, _2));
}
There is a way to do what you want, but you need to use a small adaptor. As the STL doesn't write it for you, can can write it yourself:
template <class Base, class T>
struct adaptor_t
{
typedef bool (Base::*method_t)(const T& t1, const T& t2));
adaptor_t(Base* b, method_t m)
: base(b), method(m)
{}
adaptor_t(const adaptor_t& copy) : base(copy.base), method(copy.method) {}
bool operator()(const T& t1, const T& t2) const {
return (base->*method)(t1, t2);
}
Base *base;
method_t method;
}
template <class Base, class T>
adaptor_t<Base,T> adapt_method(Base* b, typename adaptor_t<Base,T>::method_t m)
{ return adaptor_t<Base,T>(b,m); }
Then, you can use it:
doSort() { std::sort(arr,arr+someSize, adapt_method(this, &doCompare)); }
The third argument in the calling of std::sort() is not compatible to the function pointer needed by std::sort(). See my answer to another question for a detailed explanation for why a member function signature is different from a regular function signature.
just make your helper function, static which you are going to pass inside the sort function.
for e.g
struct Item
{
int val;
int id;
};
//Compare function for our Item struct
static bool compare(Item a, Item b)
{
return b.val>a.val;
}
Now you can pass this inside your sort function
A very simple way to effectively use a member function is to use operator<. That is, if you have a function called compare, you can call it from operator<. Here is a working example:
class Qaz
{
public:
Qaz(int aX): x(aX) { }
bool operator<(const Qaz& aOther) const
{
return compare(*this,aOther);
}
static bool compare(const Qaz& aP,const Qaz& aQ)
{
return aP.x < aQ.x;
}
int x;
};
Then you don't even need to give the function name to std::sort:
std::vector<Qaz> q;
q.emplace_back(8);
q.emplace_back(1);
q.emplace_back(4);
q.emplace_back(7);
q.emplace_back(6);
q.emplace_back(0);
q.emplace_back(3);
std::sort(q.begin(),q.end());
Updating Graham Asher answer, as you don't need the compare but can use the less operator directly.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Qaz {
public:
Qaz(int aX): x(aX) { }
bool operator<(const Qaz& aOther) const {
return x < aOther.x;
}
int x;
};
int main() {
std::vector<Qaz> q;
q.emplace_back(8);
q.emplace_back(1);
q.emplace_back(4);
q.emplace_back(7);
q.emplace_back(6);
q.emplace_back(0);
q.emplace_back(3);
std::sort(q.begin(),q.end());
for (auto& num : q)
std::cout << num.x << "\n";
char c;
std::cin >> c;
return 0;
}