13

Needless to over explain. The following code is self-evident:

struct X
{
    X(int n){}
};

int main()
{
    std::vector<int> src;
    std::vector<X>   dest;

    // Below is not valid in current C++, but that is just what I want.
    transform(src.begin(), src.end(), back_insert(dest), std::bind(&X::X, _1)); 
}

A constructor takes some arguments and returns an object of the class of the constructor.

A constructor looks like a function, acts like a function, and is exactly a function.

So, I think std::bind should uniformly treat constructors and other callable objects.

However, how can I extend the function template "bind" to implement that?

xmllmx
  • 39,765
  • 26
  • 162
  • 323
  • 3
    A constructor looks like a function without a return type and with some special syntax (ctor initializer), kinda acts like a function, but is not exactly a function. – Fred Nurk Nov 29 '10 at 08:45
  • A constructor is a function, that's not the problem. The problem is obtaining a function _pointer_ to it. `&X::X` just isn't a valid expression. – MSalters Nov 29 '10 at 11:57
  • [Using boost::bind with a constructor](http://stackoverflow.com/q/1335301/511601) – Fred Nurk Nov 29 '10 at 11:58
  • @MSalters: You don't use the function call operator with ctors, see C++03 §5.2.3 (among others). Ctors are treated similarly, but are not exactly like functions; and that is the source of xmllmx's confusion. – Fred Nurk Nov 29 '10 at 12:01
  • @Fred Nurk: I know. Constructors have to be functions, else a lot of language in the standard wouldn't work. For instance, they have function bodies. Your second remark correctly identifies the culprit. You can't bind them, even though they're functions, because it takes a different syntax to call them. – MSalters Nov 29 '10 at 15:31
  • Actually, not only are constructors not functions I remember witnessing a huge argument about whether or not it's even possible to 'call' them. Although with certain constructs, like initialization and casting, you can cause a chain of events to transpire that eventually result in a constructor being invoked, there's no method by which to do so directly. This is quite different from a function in just about any way you might define the word 'function'. – Edward Strange Nov 30 '10 at 08:22

5 Answers5

15

Since X is implicitly constructible from int, a simple copy should achieve the conversion.

copy(src.begin(), src.end(), std::back_inserter(dest)); 

Or even using the vector's constructor:

std::vector<X>   dest(src.begin(), src.end());

In the general case, boost's lambda library has a constructor functor.

#include <boost/lambda/bind.hpp>
#include <boost/lambda/construct.hpp>
...
using namespace boost::lambda;
transform(src.begin(), src.end(), std::back_inserter(dest), bind(constructor<X>(), _1));

In this particular case binding might not be necessary, since there is only one argument to constructor.

visitor
  • 8,564
  • 2
  • 26
  • 15
7

I don't know if there are cooler Boost ways, but you could write something like this:

class Builder
{
    X operator() (int value) const { return X(value); }
};

transform(src.begin(), src.end(), back_insert(dest), Builder()); 
Simone
  • 11,655
  • 1
  • 30
  • 43
  • This is a trivial solution and not what I want. I hope to implent that by extending bind. In other words, I don't need to define another function object class for every such case. – xmllmx Nov 29 '10 at 08:50
  • 6
    I can't see what's wrong with *trivial* solution if they work. Do we always need to write complex things? – Simone Nov 29 '10 at 08:55
  • Please refer to visitor's solution above. That's exactly what I want. – xmllmx Nov 29 '10 at 08:58
3

A constructor is a member function.

A member function needs an object to be bound to.

A constructor is only called for a not-yet-existing object, so there can never be an object to bind the constructor to.

In your case, the constructor arguments (the int values from src) should go to (a possible) back_inserter that calls the non-default ctor and not to std::transform. (EDIT: this is only true for non-copy-ctor usage)

Actually, what you want to do here is to call std::copy:

std::copy(src.begin(), src.end(), std::back_inserter(dest)); 
Martin Ba
  • 37,187
  • 33
  • 183
  • 337
  • I know there are many ways to implement what I want to do in the example code. However, I want to know how to make bind treat a constructor just as a fucntion. Because a constructor can be taken as a type-conversion function. – xmllmx Nov 29 '10 at 08:44
1

Build a factory function. These are static member functions or stand-alone functions that also construct objects, usually after validating inputs. They're useful whenever you want to ensure your objects cannot be built with invalid input (after all, you cannot abort construction within a ctor).

Since a factory is an ordinary function, you can easily bind to it to get the same effect you appear to want- a bound function that builds objects.

class X
{
public:
   X(OtherObject a, OtherData data);
   virtual ~X() {}
};

// Factory- return "X" instead of "X*" if not using the heap
X* CreateX(OtherObject a, OtherData data) {
    /*
        Logic that checks a, data for validity...
    */
    if(invalid) {
       return 0;   // You get no object
    }
    return new X();
}

Now you just bind to "CreateX" to build objects. It is a normal function, however, not a constructor so all the normal rules for functions apply- especially those for copy and move construction of objects.

Zack Yezek
  • 1,408
  • 20
  • 7
1

A constructor takes some arguments and returns an object of the class of the constructor.

No, a constructor does not return anything, and there is no such thing as a pointer to a constructor.

fredoverflow
  • 256,549
  • 94
  • 388
  • 662
  • X v1; v1 = X(8); // X(8) returns an object of class X – xmllmx Nov 29 '10 at 11:36
  • 4
    @xmllmx: No, it doesn't, really. C++ has a very clear definition of many terms, such as "to return". `X(8)` is an expression, and it _has_ type `X`. Expressions don't "return" things as they might not even be functions. I.e. the expression `3+4` is not a function call. – MSalters Nov 29 '10 at 12:02
  • the expression 3+4 is not a function call. ??? Is it not equal to operator +(3, 4) ? – xmllmx Nov 29 '10 at 13:44
  • @xml: No, it isn't. If it were, `operator+(3, 4)` would compile (which it doesn't). – fredoverflow Nov 29 '10 at 16:39