passing functor or function to template class

Discussion in 'C++' started by christof.warlich1@gmail.com, Jul 10, 2012.

  1. Guest

    Hi,

    I'm working at a generic library that must accept either function pointers or functors to be passed to a template class. This works quite straight forward as long as both are being passed by value. But as the functors that need to be passed may not be copyable, I'd like to pass functors by reference.. But doing this breaks the function pointer case. Although I could fix this by partial specialization (see code below), this looks rather clumpsy to me: It there a better way to deal with this situation? Take into account that my template class is quite big, so that specializing causes quite some code duplication.

    Thanks for any ideas,

    Chris

    #include <iostream>
    // A function.
    void *function() {
    std::cout << "function" << std::endl;
    return 0;
    }
    // A functor.
    struct Functor {
    void *operator()() {
    std::cout << "functor" << std::endl;
    return 0;
    }
    } functor;
    // Both classes (struct Value and struct Reference) may
    // be instantiated with either a function or a functor.
    template<typename T> struct Value {
    Value(T t):f(t) {}
    T f;
    };
    template<typename T> struct Reference {
    Reference(T &t):f(t) {}
    T &f;
    };
    // Partial specialization of struct Reference for
    // (function) pointers).
    template<typename T> struct Reference<T *> {
    Reference(T t):f(t) {}
    T *f;
    };
    // Test if it works.
    int main() {
    Value<void *(*)()> vf(function);
    Value<Functor> vF(functor);
    vf.f();
    vF.f();
    Reference<void *(*)()> rf(function);
    Reference<Functor> rF(functor);
    rf.f();
    rF.f();
    return 0;
    }
    , Jul 10, 2012
    #1
    1. Advertising

  2. On Tuesday, 10 July 2012 10:14:58 UTC-4, Christof Warlich wrote:
    > Hi,
    >
    > I'm working at a generic library that must accept either
    > function pointers or functors to be passed to a template class.
    > This works quite straight forward as long as both are being
    > passed by value. But as the functors that need to be passed
    > may not be copyable, I'd like to pass functors by reference.


    I think the correct approach is a bit different than your
    solution.

    - you should have a generic function wrapper (see std::function),
    that is only concerned providing wrapper functionality on
    a callable object.
    - auxiliary facility to wrap non-copy-able objects ( see std::ref
    and std::cref) by storing a reference - when possible.

    Luckily C++11 (or Boost if you do not have C++11 compile) gives
    you all the tools. See the modified version of your example:

    #include <iostream>
    #include <functional>

    void *function()
    {
    std::cout << "function" << std::endl;
    return 0;
    }

    struct Functor
    {
    private:
    Functor( const Functor& );

    public:
    Functor(){}

    void *operator()()
    {
    std::cout << "functor" << std::endl;
    return 0;
    }
    } functor;



    int main() {
    std::function<void ()> vf = function;
    std::function<void ()> vF = std::ref( functor );
    vf();
    vF();
    std::function<void ()> rf = std::ref( function );
    std::function<void ()> rF = std::ref( functor );
    rf();
    rF();
    return 0;
    }

    Note: of course in this case you would not write

    std::ref( function )

    but it is possible, and will not yield to an error.


    Ofc. you can replicate these tools if needed, and
    by separating the concerns as described above,
    should be able to get rid of the problematic
    code-duplication you mentioned.


    PS: Btw. I'd like to note that the usual definition of
    functors have the requirement of assignable (http://www.sgi.com/tech/stl/Assignable.html), but of course
    I accept that in some cases you might want to store it by
    reference, but that probably indicate some design issues...

    -- Zoltan
    Zoltan Juhasz, Jul 10, 2012
    #2
    1. Advertising

  3. Many thanks for your suggestions; you are right, this avoids the code duplication caused by the specialization. But the price to pay is that now, the user of the interface has to provide the appropriate functionality to handle noncopyable objects: The example below shows that everything is fine as long as the callable object is either a function or a copyable functor, but that (from the user's point of view) quite some hackery is required for noncopyable functors.

    Any ideas how this could be avoided, if possible not using more than tr1?

    #include <iostream>
    #include <tr1/functional>
    // A function.
    const char *function() {return "function\n";}
    // A copyable functor.
    struct CopyableFunctor {
    const char *operator()() {return "copyableFunctor\n";}
    } copyableFunctor;
    // A non-copyable functor.
    struct NoncopyableFunctor {
    NoncopyableFunctor() {}
    const char *operator()() {return "noncopyableFunctor\n";}
    private:
    NoncopyableFunctor(const NoncopyableFunctor &);
    } noncopyableFunctor;
    // May be instantiated with either a function or a copyable functor.
    template<typename T> struct Value {
    Value(T t):callable(t) {}
    T callable;
    };
    // Test if it works.
    int main() {
    Value<const char *(*)()> f1(function);
    Value<CopyableFunctor> f2(copyableFunctor);
    // If the functor is non-copyable, the hackery below is required.
    Value<std::tr1::function<const char *()> > f3(std::tr1::ref(noncopyableFunctor));
    std::cout << f1.callable();
    std::cout << f2.callable();
    std::cout << f3.callable();
    return 0;
    }
    Christof Warlich, Jul 11, 2012
    #3
  4. On Wednesday, 11 July 2012 03:58:26 UTC-4, Christof Warlich wrote:
    > Many thanks for your suggestions; you are right, this avoids the
    > code duplication caused by the specialization. But the price to
    > pay is that now, the user of the interface has to provide the
    > appropriate functionality to handle noncopyable objects


    I'd like to note that your original example also suffers from
    that problem, you had to separately handle the store-by-value
    and store-by-reference case (using Value and Reference class
    templates).

    I think using std::ref on the caller side is not hack, but
    explicit expression of intention, which might have important
    consequences. The caller needs to realize that the provided object will
    be stored as reference, therefore he must ensure that the argument
    outlives the wrapper object.


    How about storing the argument as reference (possibly using std::ref)
    or as a pointer in all cases? You can store copy-, and non-copy-able
    objects in the same way. Ofc. the caller must abide certain lifetime
    requirements in that case (e.g. temporary anonymous objects
    will not be usable).


    Alternative C++11 solution could be this: if I understand correctly,
    you'd like to completely hide the decision on storage from user.

    Currently the decision (whether to indirectly store the argument
    by value or reference) is explicitly expressed by the caller by
    wrapping the non-copy-able objects into std::ref.

    I think this decision could be done automatically, by checking
    if the object is copy-assignable (see std::is_copy_assignable in
    <type_traits>). If it is copy-assignable, then you can
    store by value, store by reference otherwise.

    This means you'll have two 'Value' specialization, one with

    T callable;

    and

    std::reference_wrapper<T> callable;

    in a partial specialization of 'Value'.


    The only problem is that this solution requires a C++11
    compiler with support for <type_traits> (20.9 Metaprogramming
    and type traits), and I am not sure if that exists at
    this point at all; might be good idea to keep in mind
    for future refinement of your code.


    As far as I know you cannot implement is_copy_assignable in C++98/03;
    e.g. the ellipsis failover technique does not work, since access
    checking happens before SFINAE could be triggered and produces an error
    (instead of failing-over to the ellipsis):

    typedef char false_type;
    struct true_type
    {
    char s[2];
    };


    template < typename T >
    true_type is_copyable_impl ( T );
    false_type is_copyable_impl ( ... );

    int main()
    {
    std::cout << sizeof( is_copyable_impl( function ) ) << std::endl;
    std::cout << sizeof( is_copyable_impl( copyableFunctor ) ) << std::endl;

    // triggers access violation when copy-ctor is private
    std::cout << sizeof( is_copyable_impl( noncopyableFunctor ) ) << std::endl;
    }


    I think that the cleanest approach is still std::func and explicit
    std::ref.

    -- Zoltan
    Zoltan Juhasz, Jul 11, 2012
    #4
  5. Am Mittwoch, 11. Juli 2012 21:10:18 UTC+2 schrieb Zoltan Juhasz:
    > On Wednesday, 11 July 2012 03:58:26 UTC-4, Christof Warlich wrote:
    > &gt; Many thanks for your suggestions; you are right, this avoids the
    > &gt; code duplication caused by the specialization. But the price to
    > &gt; pay is that now, the user of the interface has to provide the
    > &gt; appropriate functionality to handle noncopyable objects
    >
    > I'd like to note that your original example also suffers from
    > that problem, you had to separately handle the store-by-value
    > and store-by-reference case (using Value and Reference class
    > templates).

    Yeah, but the distinction is done on the library side, being transparent inthe calling code.
    >
    > I think using std::ref on the caller side is not hack, but
    > explicit expression of intention, which might have important
    > consequences. The caller needs to realize that the provided object will
    > be stored as reference, therefore he must ensure that the argument
    > outlives the wrapper object.

    Right, this a second reason (besides the code duplication) why I feel uncomfortable with my initial approach.
    >
    >
    > How about storing the argument as reference (possibly using std::ref)
    > or as a pointer in all cases? You can store copy-, and non-copy-able
    > objects in the same way. Ofc. the caller must abide certain lifetime
    > requirements in that case (e.g. temporary anonymous objects
    > will not be usable).

    This is what I tried initially, as it would by far be the cleanest solution.. But I couldn't get the same interface to work with both functors and functions when using either references or pointers: It always worked well (for both references and pointers) for functors, but gave compile-time errors for functions. I could get along with specialization though, but this throws me back to my initial point. Any advice on how to get this right would be very much welcomed.
    >
    >
    > Alternative C++11 solution could be this: if I understand correctly,
    > you'd like to completely hide the decision on storage from user.
    >
    > Currently the decision (whether to indirectly store the argument
    > by value or reference) is explicitly expressed by the caller by
    > wrapping the non-copy-able objects into std::ref.
    >
    > I think this decision could be done automatically, by checking
    > if the object is copy-assignable (see std::is_copy_assignable in
    > &lt;type_traits&gt;). If it is copy-assignable, then you can
    > store by value, store by reference otherwise.
    >
    > This means you'll have two 'Value' specialization, one with
    >
    > T callable;
    >
    > and
    >
    > std::reference_wrapper&lt;T&gt; callable;
    >
    > in a partial specialization of 'Value'.
    >
    >
    > The only problem is that this solution requires a C++11
    > compiler with support for &lt;type_traits&gt; (20.9 Metaprogramming
    > and type traits), and I am not sure if that exists at
    > this point at all; might be good idea to keep in mind
    > for future refinement of your code.
    >
    >
    > As far as I know you cannot implement is_copy_assignable in C++98/03;
    > e.g. the ellipsis failover technique does not work, since access
    > checking happens before SFINAE could be triggered and produces an error
    > (instead of failing-over to the ellipsis):
    >
    > typedef char false_type;
    > struct true_type
    > {
    > char s[2];
    > };
    >
    >
    > template &lt; typename T &gt;
    > true_type is_copyable_impl ( T );
    > false_type is_copyable_impl ( ... );
    >
    > int main()
    > {
    > std::cout &lt;&lt; sizeof( is_copyable_impl( function ) ) &lt;&lt; std::endl;
    > std::cout &lt;&lt; sizeof( is_copyable_impl( copyableFunctor ) ) &lt;&lt; std::endl;
    >
    > // triggers access violation when copy-ctor is private
    > std::cout &lt;&lt; sizeof( is_copyable_impl( noncopyableFunctor ) ) &lt;&lt; std::endl;
    > }

    I already searched the Web for some is_copyable implementation for C++ 2003, but without success. Thanks for sheding some light on why I didn't find one :).
    >
    >
    > I think that the cleanest approach is still std::func and explicit
    > std::ref.

    Agreed, except if the interface could be done with either references or pointers for both functors and functions as discussed above.

    Anyway, again many thanks for your very valuable help.
    Christof Warlich, Jul 18, 2012
    #5
  6. After the inspiring discussion, and particularly encouraged by Zoltan's SFINAE example, I finally found the solution myself. I'm sharing it here for the record and in case someone else might be interested.

    #include <iostream>
    template<typename T> struct isFunctionPointer {
    template<typename U> static char is_ptr(U (*)());
    static double is_ptr(...);
    static T t;
    enum {value = sizeof(is_ptr(t)) == sizeof(char)};
    };
    template<typename T, bool = isFunctionPointer<T>::value> struct Type {typedef T & U;};
    template<typename T> struct Type<T, true> {typedef T U;};
    // A function.
    void *function() {
    std::cout << "function" << std::endl;
    return 0;
    }
    // A functor.
    class Functor {
    public:
    Functor() {}
    void *operator()() {
    std::cout << "functor" << std::endl;
    return 0;
    }
    private:
    Functor(const Functor &);
    } functor;
    template<typename T> struct Reference {
    Reference(typename Type<T>::U t):f(t) {}
    typename Type<T>::U f;
    };
    // Test if it works.
    int main() {
    Reference<void *(*)()> rf(function);
    Reference<Functor> rF(functor);
    rf.f();
    rF.f();
    return 0;
    }
    Christof Warlich, Jul 18, 2012
    #6
  7. Excellent solution, thanks for sharing this.

    -- Zoltan

    On Wednesday, 18 July 2012 07:15:01 UTC-4, Christof Warlich wrote:
    > After the inspiring discussion, and particularly encouraged by Zoltan's SFINAE example, I finally found the solution myself. I'm sharing it here for the record and in case someone else might be interested.
    >
    > #include &lt;iostream&gt;
    > template&lt;typename T&gt; struct isFunctionPointer {
    > template&lt;typename U&gt; static char is_ptr(U (*)());
    > static double is_ptr(...);
    > static T t;
    > enum {value = sizeof(is_ptr(t)) == sizeof(char)};
    > };
    > template&lt;typename T, bool = isFunctionPointer&lt;T&gt;::value&gt; struct Type {typedef T &amp; U;};
    > template&lt;typename T&gt; struct Type&lt;T, true&gt; {typedef T U;};
    > // A function.
    > void *function() {
    > std::cout &lt;&lt; &quot;function&quot; &lt;&lt; std::endl;
    > return 0;
    > }
    > // A functor.
    > class Functor {
    > public:
    > Functor() {}
    > void *operator()() {
    > std::cout &lt;&lt; &quot;functor&quot; &lt;&lt; std::endl;
    > return 0;
    > }
    > private:
    > Functor(const Functor &amp;);
    > } functor;
    > template&lt;typename T&gt; struct Reference {
    > Reference(typename Type&lt;T&gt;::U t):f(t) {}
    > typename Type&lt;T&gt;::U f;
    > };
    > // Test if it works.
    > int main() {
    > Reference&lt;void *(*)()&gt; rf(function);
    > Reference&lt;Functor&gt; rF(functor);
    > rf.f();
    > rF.f();
    > return 0;
    > }
    Zoltan Juhasz, Jul 18, 2012
    #7
  8. > Excellent solution, thanks for sharing this.
    Thanks, I got excellent help :).

    But unfortunately, the solution is still unusable for me as it strangely doesn't work any longer if the functor uses the Curiously Recurring Template Pattern, which I need in my real implementation.

    Below is a sample implementation showing the issue: As long as SMART isn't defined, the initial "dumb" implementation is used and everything compiles fine even when CRTP is involved, but using the new, "smart" solution, I getthe following compiler errors:

    noncopyFunctorOrFunction.cpp: In instantiation of »isFunctionPointer<X>«:
    noncopyFunctorOrFunction.cpp:25:5: instantiated from »Reference<X>«
    noncopyFunctorOrFunction.cpp:41:31: instantiated from here
    noncopyFunctorOrFunction.cpp:5:14: Error: »isFunctionPointer<X>::t« hasincomplete type
    noncopyFunctorOrFunction.cpp:41:8: Error: forward declaration of »struct X«

    #include <iostream>
    template<typename T> struct isFunctionPointer {
    template<typename U> static char is_ptr(U (*)());
    static double is_ptr(...);
    static T t;
    enum {value = sizeof(is_ptr(t)) == sizeof(char)};
    };
    template<typename T, bool = isFunctionPointer<T>::value> struct Type {typedef T & U;};
    template<typename T> struct Type<T, true> {typedef T U;};
    // A function.
    void function() {std::cout << "function" << std::endl;}
    // A functor.
    class Functor {
    public:
    Functor() {}
    void operator()() {std::cout << "functor" << std::endl;}
    private:
    Functor(const Functor &);
    } functor;
    //#define SMART
    #ifdef SMART
    // Unfortunately, this does not work together with
    // the Curiously Recurring Template Pattern ....
    template<typename T> struct Reference {
    Reference(typename Type<T>::U t):f(t) {}
    typename Type<T>::U f;
    };
    #else
    // ... while the simple-minded approach still works fine.
    template<typename T> struct Reference {
    Reference(T &t):f(t) {}
    T &f;
    };
    // Partial specialization of struct Reference for
    // (function) pointers).
    template<typename T> struct Reference<T *> {
    Reference(T t):f(t) {}
    T *f;
    };
    #endif
    struct X: public Reference<X> {
    X(): Reference<X>(*this) {}
    void operator()() {std::cout << "functor with CRTP" << std::endl;}
    } x;
    // Test if it works.
    int main() {
    Reference<void (*)()> rf(function);
    Reference<Functor> rF(functor);
    rf.f();
    rF.f();
    Reference<X> rX(x);
    rX.f();
    return 0;
    }

    Any ideas what's going wrong and how to solve it?

    Chris
    Christof Warlich, Jul 18, 2012
    #8
  9. Casey Guest

    On Wednesday, July 18, 2012 10:22:11 AM UTC-5, Christof Warlich wrote:
    > Any ideas what's going wrong and how to solve it?


    Your implementation of isFunctionPointer<T> requires T to be a complete type. At
    the point when Reference<X> is instantiated to be a base class of X, X is
    incomplete. If you replace your implementation with:

    template<typename T> struct isFunctionPointer {
    static const bool value = false;
    };
    template<typename T> struct isFunctionPointer<T(*)()> {
    static const bool value = true;
    };

    Then the compiler will be smart enough to know that incomplete types can't be
    function pointers.
    Casey, Jul 18, 2012
    #9
  10. Christof,

    Yes, that indeed breaks the CRTP as the Reference indirectly
    tries to instantiate the object when it checks for ptr.

    It turns out that you actually do not need the above-mentioned
    ellipsis, but a simple partial specialization works. That should
    work even the existence of CRTP.

    Note: I noticed that now you essentially store every functor as
    reference, I guess the life-time requirements then has to be
    made clear to the caller side.

    -- CODE --

    #include <iostream>

    template < typename T >
    struct StorageSelector
    {
    typedef T & type;
    };

    template < typename T >
    struct StorageSelector < T * >
    {
    typedef T * type;
    };

    // A function.
    void *function() {
    std::cout << "function" << std::endl;
    return 0;
    }
    // A functor.
    class Functor {
    public:
    Functor() {}
    void *operator()() {
    std::cout << "functor" << std::endl;
    return 0;
    }
    private:
    Functor(const Functor &);
    } functor;


    template<typename T>
    struct Reference
    {
    typedef typename StorageSelector< T >::type StorageT;
    Reference( StorageT t ) : f( t ) {}
    StorageT f;
    };

    struct X: public Reference<X>
    {
    X(): Reference<X>(*this) {}
    void operator()() {std::cout << "functor with CRTP" << std::endl;}
    } x;


    int main() {
    Reference<void *(*)()> rf(function);
    Reference<Functor> rF(functor);
    rf.f();
    rF.f();
    return 0;
    }

    -- /CODE --

    On Tuesday, 10 July 2012 10:14:58 UTC-4, Christof Warlich wrote:
    > Hi,
    >
    > I'm working at a generic library that must accept either function pointers or functors to be passed to a template class. This works quite straight forward as long as both are being passed by value. But as the functors that need to be passed may not be copyable, I'd like to pass functors byreference. But doing this breaks the function pointer case. Although I could fix this by partial specialization (see code below), this looks rather clumpsy to me: It there a better way to deal with this situation? Take into account that my template class is quite big, so that specializing causes quite some code duplication.
    >
    > Thanks for any ideas,
    >
    > Chris
    >
    > #include &lt;iostream&gt;
    > // A function.
    > void *function() {
    > std::cout &lt;&lt; &quot;function&quot; &lt;&lt; std::endl;
    > return 0;
    > }
    > // A functor.
    > struct Functor {
    > void *operator()() {
    > std::cout &lt;&lt; &quot;functor&quot; &lt;&lt; std::endl;
    > return 0;
    > }
    > } functor;
    > // Both classes (struct Value and struct Reference) may
    > // be instantiated with either a function or a functor.
    > template&lt;typename T&gt; struct Value {
    > Value(T t):f(t) {}
    > T f;
    > };
    > template&lt;typename T&gt; struct Reference {
    > Reference(T &amp;t):f(t) {}
    > T &amp;f;
    > };
    > // Partial specialization of struct Reference for
    > // (function) pointers).
    > template&lt;typename T&gt; struct Reference&lt;T *&gt; {
    > Reference(T t):f(t) {}
    > T *f;
    > };
    > // Test if it works.
    > int main() {
    > Value&lt;void *(*)()&gt; vf(function);
    > Value&lt;Functor&gt; vF(functor);
    > vf.f();
    > vF.f();
    > Reference&lt;void *(*)()&gt; rf(function);
    > Reference&lt;Functor&gt; rF(functor);
    > rf.f();
    > rF.f();
    > return 0;
    > }
    Zoltan Juhasz, Jul 18, 2012
    #10
  11. On Wednesday, 18 July 2012 12:12:01 UTC-4, Zoltan Juhasz wrote:
    > Yes, that indeed breaks the CRTP as the Reference indirectly
    > tries to instantiate the object when it checks for ptr.
    >
    > It turns out that you actually do not need the above-mentioned
    > ellipsis, but a simple partial specialization works. That should
    > work even the existence of CRTP.


    If you happen to have TR1 libs, it is actually even
    more simple (would be the same with C++11):


    #include <iostream>
    #include <tr1/functional>

    // A function.
    void *function() {
    std::cout << "function" << std::endl;
    return 0;
    }
    // A functor.
    class Functor {
    public:
    Functor() {}
    void *operator()() {
    std::cout << "functor" << std::endl;
    return 0;
    }
    private:
    Functor(const Functor &);
    } functor;


    template< typename T >
    struct Callable
    {
    typedef std::tr1::function< T > StorageT;
    template < typename TT >
    Callable( TT & callable )
    : invoke( std::tr1::ref( callable ) )
    {}
    StorageT invoke;
    };

    struct X: public Callable< void() >
    {
    typedef Callable< void() > BaseT;
    X(): BaseT( *this ) {}
    void operator()() {std::cout << "functor with CRTP - not anymore :)" << std::endl;}
    } x;

    int main()
    {
    Callable< void() > rf( function );
    Callable< void() > rF( functor );
    X xF;

    rf.invoke();
    rF.invoke();
    xF();

    // that fails - by pure coincident - but this
    // is good for us as Callable cannot be used
    // with temporary objects
    // Callable< void() > invalid_rF( Functor() );
    // invalid_rF.invoke();

    return 0;
    }


    My only concern with these solutions that they store
    everything as reference, thus disallow one of the most
    frequent use of functors (passing them as temporary rvalue).

    -- Zoltan
    Zoltan Juhasz, Jul 18, 2012
    #11
  12. > If you replace your implementation with:
    >
    > template&lt;typename T&gt; struct isFunctionPointer {
    > static const bool value = false;
    > };
    > template&lt;typename T&gt; struct isFunctionPointer&lt;T(*)()&gt; {
    > static const bool value = true;
    > };


    That's great: It is shorter, easier to understand and more generic than my solution. Thanks a lot.
    Christof Warlich, Jul 19, 2012
    #12
  13. > template &lt; typename T &gt;
    > struct StorageSelector
    > {
    > typedef T &amp; type;
    > };
    >
    > template &lt; typename T &gt;
    > struct StorageSelector &lt; T * &gt;
    > {
    > typedef T * type;
    > };


    And this makes it even simpler :).
    Christof Warlich, Jul 19, 2012
    #13
  14. > template&lt;typename T&gt; struct isFunctionPointer {
    > static const bool value = false;
    > };
    > template&lt;typename T&gt; struct isFunctionPointer&lt;T(*)()&gt; {
    > static const bool value = true;
    > };

    That's great! It is shorter, easier to understand and more generic than my solution. Thanks a lot!
    Christof Warlich, Jul 19, 2012
    #14
  15. > If you happen to have TR1 libs, it is actually even
    > more simple (would be the same with C++11):
    >
    > ....

    Hmm - I'm not sure if I find that more simple :), but that's maybe because I'm still not too much into the new C++0x standard.
    >
    >
    > My only concern with these solutions that they store
    > everything as reference, thus disallow one of the most
    > frequent use of functors (passing them as temporary rvalue).


    That's right, the library user should know wheather she has to take care of object lifetime. But using the tr1::function framework as you suggested earlier would overstrain my (local) users of the library.

    But how about the following sample implementation, where the library user may pass function pointers and copyable objects by value and noncopyable objects by pointer?:

    /*****************/
    /* Library code: */
    /*****************/
    #include <iostream>
    template<typename T> struct IsPointer {
    IsPointer(T f):f(f) {}
    T &f;
    };
    template<typename T> struct IsPointer<T *> {
    IsPointer(T *f):f(*f) {}
    T &f;
    };
    // Some generic library function accepting
    // all sorts of callable objects.
    template<typename Callable> void print(Callable func) {
    IsPointer<Callable> p(func);
    std::cout << p.f() << std::endl;
    // But how can an assignment like the
    // following be made to work for all
    // types of callable objects?
    //Callable *x = &(p.f);
    }
    /*********************/
    /* Application code: */
    /*********************/
    // A function.
    const char *function() {return "function";}
    // A copyable functor.
    struct CopyableFunctor {
    const char *operator()() {return "copyable functor";}
    } copyableFunctor;
    // A noncopyable functor.
    class NonCopyableFunctor {
    public:
    NonCopyableFunctor() {}
    const char *operator()() {return "noncopyable functor";}
    private:
    NonCopyableFunctor(const NonCopyableFunctor &);
    } nonCopyableFunctor;
    // Test it:
    int main() {
    print(function);
    print(copyableFunctor);
    print(&nonCopyableFunctor);
    return 0;
    }

    Note that I switched to a function template for the "library interface" to show that template deduction works fine as well. The only concern with this approach
    is pointed out in the code comments above: How may I make assignments with my callable objects that work for all types (i.e. funtions, functors and pointers to functors)?

    Cheers,

    Chris
    Christof Warlich, Jul 19, 2012
    #15
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Chandra Shekhar Kumar

    functor object in template class

    Chandra Shekhar Kumar, Jun 24, 2003, in forum: C++
    Replies:
    5
    Views:
    1,272
    porschberg
    Jun 26, 2003
  2. CoolPint
    Replies:
    3
    Views:
    711
    tom_usenet
    Dec 29, 2003
  3. James Aguilar
    Replies:
    11
    Views:
    515
    Pete Becker
    Mar 30, 2005
  4. christopher diggins
    Replies:
    16
    Views:
    750
    Pete Becker
    May 4, 2005
  5. 邹俊洋
    Replies:
    0
    Views:
    191
    邹俊洋
    Aug 12, 2013
Loading...

Share This Page