1

I've been exploring many of the new features of C++ 11 in Visual Studio 2013 Pro. So far I gotta say it kicks ass, but I hit a snag in my research and I was hoping I could raise mu hand and get some help. (Big fan of this site, first time posting, sorry if code isn't set up right).

Currently, I'm trying to create a generic method of binding a function and/or member function ( operator () ) to an encapsulated instance of std::function.

I'm using a variadic template argument to deal with variable argument lists, drawing the number of arguments via the size of the variadic, and using the value in compile-time recursion in order to pump/return the correct number of placeholders into the bind operation.

Because std::bind needs an instance and not a type, the compile-time recursion helpers are just returning instances of std::_Ph <N>. I use a specialization of the helper ( std::_Ph<1> ) as a delimiter, otherwise it just turns into an infinite loop that floods the call-stack during compilation.

Here is an example of the experiential code I'm working with:

//Nothing special, just a polymorphic base
class iObject {

     public:

          virtual ~iObject () {};

};

/*Again nothing special, just a default null object implementation of an object that overloads operator ()*/
template < typename RETURN_TYPE, typename ... ARGS > 
class BaseCall : public iObject {

     public:

          ~BaseCall () {};

          virtual RETURN_TYPE operator () ( ARGS ... args ) {

               return 0;

          };

};

//One more bit of testing fodder, a concrete implementation of BaseCall
template < typename RETURN_TYPE, typename ... ARGS >
struct SampleMax : public BaseCall < RETURN_TYPE, ARGS ... > {

     private:

          /*deals with error C2903: 'result' : symbol is neither a class template not a function template*/
          typedef RETURN_TYPE result_type;

     //Inverted template method + trailing return
     protected:

          //Function assumes we are working with a sorted STL container
          template < typename FIRST_ARG >
          inline auto Implementation ( FIRST_ARG & Sample ) -> result_type {

               return * ( Sample.rbegin() );

          };

     public:

          /*For all public operator () members like this the code would be the same
          result_type operator () ( ARGS ... args ) {

               return Implementation ( args ... );

          };

};

//My compile-time helpers
//Got the idea from here: 
 //http://stackoverflow.com/questions/8759872/compile-time-recursion-and-conditionals

template < int N >
std :: _Ph < N > * CTRecursivePlaceholder () {

     return new std :: _Ph < N - 1 >;

};

//Specialization
template <>
std :: _Ph < 1 > * CTRecursivePlaceholder < 1 > () {

     return new std :: _Ph < 1 >;

};

//Here's the beef
template < typename RETURN_TYPE, typename ...ARGS >
class Experiment {

     public:  /*Ideally private, but for testing purposes it doesn't really matter right now*/

          std :: function < RETURN_TYPE ( ARGS ... ) Receiver;

    public:

          Experiment () {

               Receiver = std :: bind ( BaseCall < RETURN_TYPE, ARGS ... > (), * ( CTRecursivePlaceholder < ( sizeof ... ( ARGS ) ) > () ) );

          };

          virtual ~Experiment () {};

};

PROBLEM #1: In instances where only a single argument is required, creating an instance works normally, as well as binding and calling a standalone function:

/*pretend a vector of doubles called vec exists so I don't have to write it ;)*/

//...somewhere in a header...
double func ( std :: vector < double > & k )
{ return 1.0f; };

//...somewhere in a source file...
Experiment < double, std :: vector < double > & > exp;  //<-- instantiates just fine

exp.Receiver = & func;  //works
exp.Receiver ( vec );  //works

However, when I try to assign the std::function data member to a child of BaseCall such as my SampleMax functor like so:

SampleMax < double, std :: vector < double > & > max;

exp.Reciever = & max; //no go

I get error C2064: term does not evaluate to a function taking 1 arguments. The error originates from , inside of the xrefwrap header.

If I use placeholders outright inside of the Experiment constructor, it'll work.

PROBLEM #2: Across the board ( standalone functions & member functions ), if I try to create an instance of Experiment with a signature of two arguments or more, like so:

//...somewhere in a source file...
Experiment < double, std :: vector < double > &, std :: vector < double > & > exp;

I get the following error ( C2440 ):
'return' : cannot convert from 'std :: _Ph < 1 > *' to 'std :: _Ph < 2 > *'

If I remember correctly, specializations will always take precidence to the compiler over template definitions, so it could be that it's going after the specialization instead of the template definition.

I'm also not so sure about the 'N - 1' statement in the template definition of std::_Ph, because it should be performing the arithmetic before it creates the instance, but that's how the example ran through it so I did the same.

Pardon any typo's, I wrote this whole thing on my phone, and thanks for any help you can give!

Jerry YY Rain
  • 4,134
  • 7
  • 35
  • 52
Janus
  • 125
  • 1
  • 8
  • 1
    `std::_Ph`? Sounds nonportable. [Here's a portable solution](http://stackoverflow.com/q/21192659/420683) – dyp Jun 30 '14 at 13:40
  • I don't quite understand why `CTRecursivePlaceholder` uses `new`, returns a pointer, and where the recursion is intended to take place. – dyp Jun 30 '14 at 13:47
  • As far as I can tell, a pointer to an object like `&max` is not callable. `max` itself is callable, but `exp.Receiver = max` will copy `max`. OTOH, `exp.Receiver = std::ref(max)` will store a reference to `max`. – dyp Jun 30 '14 at 13:57
  • std::_Ph < N > is a standard STL type, if you've used std::placeholders::_1then you've used type of std::_Ph < N >. Unless there are aspects to the STL that are not portable, which would be news to me. I have to return an instance of the type, hence new. If I tried to return a local instance it would go out of scope. Recursion is happening inside the bind call – Janus Jun 30 '14 at 14:02
  • 1
    The name `_Ph` does not appear neither in the official C++11 Standard nor in n3797 (a fairly recent C++1y draft). It is most probably an implementation detail of the Standard Library implementation you're using. *"I have to return an instance of the type, hence new"* and *"If I tried to return a local instance it would go out of scope."* Basic C++ 101: *value semantics*. You can pass and return *by value*. `new` is not required. – dyp Jun 30 '14 at 14:08
  • You got a point there with the value semantics,, it'll likely simplify the call, but it's not going to fix the two root problems. The _Ph type isn't new, it's a little arcane but not new. Unless its some Windows specific type, I'll have to look into it – Janus Jun 30 '14 at 14:12
  • No _Ph is standard STL, it's existed as long as std::bind has – Janus Jun 30 '14 at 14:29
  • It is not standard if it's not in the C++ Standard. Placeholders are standard, i.e. the `std::placeholders` namespace and its members `_1` etc. Similarly `std::bind`. – dyp Jun 30 '14 at 14:33
  • Well, we're probably just arguing semantics but std :: placeholders :: _1 is the same as std :: _Ph < 1 >, if I were to hand code it for every possible length of the argument signature I could use both interchangeably, and if you right-click on _1 and view its definition (which is how I found it some time ago) you'll see that _N are all of type _Ph < N > – Janus Jun 30 '14 at 14:40
  • 1
    `std::_Ph` is part of the *implementation details* of Microsofts/Dinkumware's implementation of the Standard Library. Try compiling your code with g++/libstdc++ or clang++/libc++ and you will notice that they don't have any `std::_Ph`. That's why it is not portable. On the other hand, `std::placeholders::_1` etc. *are standard*, which means you're guaranteed to have them in any implementation of the Standard Library. – dyp Jun 30 '14 at 15:03

1 Answers1

0

Problem #1 was already solved in dyp's comment

Problem #2 is that you return std::_Ph<1>* where a std::_Ph<2>* is expected.

Simply substitute 2 for N here

template < int N >
std :: _Ph < N > * CTRecursivePlaceholder () {

     return new std :: _Ph < N - 1 >;

};

and you'll see that.

Addendum July 2nd 2014

Here's an ansatz for recursive construction of a bind.

#include <functional> // bind, is_placeholder
/*[...]*/    

// placeholder
template<int N> struct PH {};

// It's ugly to extend std,
// but there's no other way to make arbitrary 
// placeholders known to std::bind
namespace std {
    template<int N>
    struct is_placeholder<PH<N>> 
        : public integral_constant<int, N> {};
}

// recursive sequential binder
// this simply pushes the placeholder types into the Args 
// result is in-order
template<class F, int N, class... Args>
struct SeqBinder : public SeqBinder<F, N-1, PH<N>, Args...> {};

// recursive sequential binder terminator specialization
template<class F, class... Args>
struct SeqBinder<F, 0, Args...> {
    static auto bind(F&& f)
        /*
         * HINT
         * here is the point to insert whatever invariant params
         * to the bind
         */
        -> decltype(std::bind(f, /* +whatever ,*/ Args()...)) {
             return std::bind(f, /* +whatever ,*/ Args()...); 
    } // bind()
}; // SeqBinder (terminator specialization)

You have to customize/extend that to make it suit your needs; pls note that in principle it's rather pointless binding the N parameters of N-ary callable to N placeholders in-sequence, because that is their natural bind.

Another addendum And pls keep in mind that the signed int template parameter is a potential problem for recursions terminating at 0; you should take measures to capture negative N erroneously provided.

Solkar
  • 1,228
  • 12
  • 22
  • @dyp OK, sorry dyp, wasn't getting where you where going with that, returning by value seems to fix problem one. Both of the helpers now define a local instance an return by value. And the code seems to work on both stand alone and class functions. Still having trouble with an argument list that is two or longer – Janus Jul 01 '14 at 16:45
  • I understand that I'm returning std::_Ph<1>* where a std::_Ph<2>* is expected, but I thought the compile-time recursion would be able to handle that. Is it the < N - 1 > statement? – Janus Jul 01 '14 at 16:47
  • Sure. _Ph*N=*/2> is neither the same as, nor an ancestor of _Ph*N-1=*/1>. – Solkar Jul 01 '14 at 17:36
  • I know what your trying to get me to do, you want me to to change the return type template arg from N to N - 1, but that won't compile. I've tried trailing return types, nesting the call in a struct, and a few other refactors, but no dice. At least in Visual Studio 2013 Pro, there is no solution that is not verbose. I can't use constexp (precompiled expression), and std :: integer_sequence would be the other two routes I would take, but neither will be available in VS until November. Guess I'll have to wait till then. Thanks anyway. – Janus Jul 02 '14 at 06:06
  • I'm not trying to "get [you] to do" anything. Pls note the addendum of my answer. – Solkar Jul 02 '14 at 18:09
  • You wouldn't happen to know where I can get a good in-depth on type_traits would you? – Janus Jul 03 '14 at 00:36
  • http://en.cppreference.com/w/cpp/types has some instructive samples. And Stroustrup, B. The C++ programming language. Addison-Wesley, 2013., of course. (The **2013** edition! Not an earlier one!). – Solkar Jul 03 '14 at 04:30