1

I am trying to call a member function on each object in a vector, with a specified parameter, and I would like the call to be polymorphic. I believe the function vstuff shown below achieves this. But can vstuff be modified to take a vector< shared_ptr < Base> > without using boost::bind?

class Base{
            virtual double stuff(double t);
           }
//and some derived classes overriding stuff
//then in some code 
vector<double> vstuff(double t, vector<Base*> things)
{
vector<double> vals;
vals.resize(things.size());
transform(things.begin(), things.end(), vals.begin(), std::bind2nd(std::mem_fun(&Base::stuff),t));
return vals;
}

I know that shared_ptr s require mem_fn instead of mem_fun , but I have not succeeded in making mem_fn work with the bind2nd I need to pass in the parameter t, so I wonder whether or not it is feasible.. ?

Pradhan
  • 16,391
  • 3
  • 44
  • 59
imateapot
  • 141
  • 1
  • 1
  • 8
  • Why not use lambdas? – Lol4t0 Mar 08 '15 at 22:14
  • I'd like to understand how to do this with minimal boost usage, and the project is not C++11. – imateapot Mar 08 '15 at 22:36
  • 2
    Why do you want to use std::transform at all and not a simple loop? – MikeMB Mar 08 '15 at 23:09
  • @MikeMB `std::transform` indicates that the order in which the elements are processed does not matter. – Neil Kirk Mar 09 '15 at 02:38
  • @Neil Kirk: yes, but I don't see how that is an advantage. – MikeMB Mar 09 '15 at 08:28
  • @MikeMB It indicates information to the programmer at a glance and allows more compiler optimizations. – Neil Kirk Mar 09 '15 at 10:23
  • @MikeMB in addition to what Neil Kirk said, I imagine that the solution for std::transform would also be of use with other stl algos less easy to rewrite oneself everywhere, such as std::sort. – imateapot Mar 09 '15 at 10:45
  • @Neil Kirk: Do you have any material supporting you claim? The STL implementations I know implement transform in terms of a loop and as the compiler has to treat the stl like any other user provided library, I don't see how that should enable additional optimizations. I'd also challange your statement that the transform version provides more information "at a glance" due to the added complexity of bind, mem_fun and member function pointer. That additional complexity actually might prevent some optimizations if the compiler is not smart enough. – MikeMB Mar 09 '15 at 11:01
  • @MikeMB Why wouldn't the compiler be smart enough to optimize its own standard library? I agree the syntax is obtuse, it is less so in C++11. http://en.cppreference.com/w/cpp/algorithm/transform `std::transform does not guarantee in-order application of unary_op or binary_op.` – Neil Kirk Mar 09 '15 at 11:22
  • @Neil Kirk: Let me rephrase that: An standard library implementation might be tailored to the specifics of the compiler it is used with and vice versa, but a compiler will - to my knowledge - NOT treat `std::transform` as a keyword and apply special optimizations for it that are not based on the actual implementation code but on knowledge about the standard’s requirements. Adding additional indirection might not hurt, but I don't see how it helps here either. – MikeMB Mar 09 '15 at 12:28
  • @imateapot: Although sort might not be the best example either, because I'd rather overload the comparison operator, I agree that it might be helpfull in other contexts and I'm glad that sehe provided an actual answer to your question. I'm also not saying, that `std::transfrom` is useless in general (I mostly use it as a building block for my own generic STL-style algorithms). I was just wondering whether it offers any benefits in your particular example that I didn't see and that would justify jumping through all those hoops. – MikeMB Mar 09 '15 at 12:38
  • @MikeMB What's to stop the compiler allowing functions to be tagged with special flags to guide optimization as an *extension* and then providing these tags on its standard library functions? – Neil Kirk Mar 09 '15 at 13:06
  • @Neil Kirk: I have never said that it is not possible/not allowed to add compiler specific flags I only said that they would not be exclusive to the standard library and more importantly - to the best of my knowledge - it is not done. I just haven't seen any optimizations and also can't think of any. You stated that std::transform allows more compiler optimizations: Can you give any CONCRETE example or provide a benchmark that shows `std::transform` is faster than a simple loop IN THIS context? – MikeMB Mar 09 '15 at 13:46
  • @MikeMB I'm not aware of any concrete examples. :( – Neil Kirk Mar 09 '15 at 14:06

1 Answers1

0

You can use std::bind too (or lambdas):

Live On Coliru

#include <algorithm>
#include <vector>
#include <memory>

struct Base {
    virtual double stuff(double) { return 0; }
};

struct Threes : Base {
    virtual double stuff(double) { return 3; }
};

struct Sevens : Base {
    virtual double stuff(double) { return 7; }
};

std::vector<double> vstuff(double t, std::vector<std::shared_ptr<Base> > things)
{
    std::vector<double> vals;
    vals.resize(things.size());
    transform(things.begin(), things.end(), vals.begin(), std::bind(&Base::stuff, std::placeholders::_1, t));
    return vals;
}

#include <iostream>

int main() {
    for (double v : vstuff(42, {
                std::make_shared<Sevens>(),
                std::make_shared<Sevens>(),
                std::make_shared<Sevens>(),
                std::make_shared<Threes>(),
                std::make_shared<Sevens>(),
                std::make_shared<Threes>(),
                std::make_shared<Sevens>(),
                std::make_shared<Sevens>(),
                std::make_shared<Threes>(),
                std::make_shared<Sevens>(),
            }))
    {
        std::cout << v << " ";
    }
}

Prints

7 7 7 3 7 3 7 7 3 7 
sehe
  • 374,641
  • 47
  • 450
  • 633