Storing a member function pointer from an arbitrary class as an instance variable of a class

There are several questions about SO that address function pointers as parameters / arguments ( here , here , here , etc.). Actually, I asked a question. However, this question is slightly different.

My problem is that I am writing a class that I want to be extremely flexible.

What works for me now for non-member functions. It is posted below.

template <typename T>
class MyClass
{
    private:
        typedef double (*firstFunctionPtr) (const T &var);

        typedef bool (*secondFunctionPtr)(const T &var);

        // Function pointers as member variables
        firstFunctionPtr _firstFunc;
        secondFunctionPtr _secondFunc;

    public:
        inline MyClass(firstFunctionPtr firstFunc, 
            secondFunctionPtr secondFunc);
};

template<typename T>
MyClass<T>::MyClass(firstFunctionPtr firstFunc, secondFunctionPtr secondFunc) :
    _firstFunc(firstFunc),
    _secondFunc(secondFunc),
    {}

However, this falls apart when I need to initialize a pointer to a member function of some other, arbitrary class, which, unfortunately, for me, is a common use case for my purposes.

This answer suggests that

++- , - .

. typedefs ( ++ 11), -, .

Q/A, , , , .

  • - , , -, ?
  • , , -, - ?
  • , ?

functional, , .

+4
3

, MyClass , :

double (*)(const T &var);
bool (*)(const T &var);

T , , - :

double (C::*)(const T &var);
bool (C::*)(const T &var);

C T, MyClass T C :

  • C -
  • C -

(1) non-class C -, .

(2) C , -, --.

C void. C void:

template<typename T, typename C = void>
struct MyClass;

, :

MyClass<T>

T :

MyClass<T,C>

C, void, -.

, std::enable_if SFINAE, , , U . , , :

, :

template<typename T>
struct MyClass<T>
{
    ... for free function pointers ...
};

template<typename T, typename C>
struct MyClass<T,C>
{
    ... for member function pointers ...
};

, - "" , . , , .

, , , , .

template <typename T, typename C = void, typename Default = void> 
struct MyClass;

, :

// Primary template
template <typename T, typename C = void, typename Default = void> 
struct MyClass;

// Free function specialization
template <typename T>
struct MyClass<T>
{
    using firstFunctor_t = double(*)(T const &);
    using secondFunctor_t = bool(*)(T const &);

    MyClass(firstFunctor_t firstFunc, secondFunctor_t secondFunc)
    :   _firstFunc(firstFunc),
        _secondFunc(secondFunc)
    {}

    double callFirst(T const & var) {
        return _firstFunc(var);
    }

    bool callSecond(T const & var) {
        return _secondFunc(var);
    }

private:

    firstFunctor_t _firstFunc;
    secondFunctor_t _secondFunc;
};

// Member function specialization
template <typename T, typename C>
struct MyClass<T,C>
{
    using firstFunctor_t = double(C::*)(T const &);
    using secondFunctor_t = bool(C::*)(T const &) const;

    MyClass(firstFunctor_t firstFunc, secondFunctor_t secondFunc)
    :   _firstFunc(firstFunc),
        _secondFunc(secondFunc)
    {}

    double callFirst(C & obj, T const & var) {
        return (obj.*_firstFunc)(var);
    }

    double callFirst(C const & obj, T const & var) {
        auto & o = const_cast<C&>(obj);
        return (o.*_firstFunc)(var);
    }

    bool callSecond(C & obj, T const & var) {
        return (obj.*_secondFunc)(var);
    }

    bool callSecond(C const & obj, T const & var) {
        auto & o = const_cast<C&>(obj);
        return (o.*_secondFunc)(var);
    }

private:

    firstFunctor_t _firstFunc;
    secondFunctor_t _secondFunc;
};

- , : -

, -, , const. , - C T const & bool const , ? , const-ness -, :

using secondFunctor_t = bool(C::*)(T const &) const;

bool (C::*)(T const &) const .

, MyClass<T,C>::callFirst MyClass<T,C>::callSecond, :

C & obj, T const & var

:

C const & obj, T const & var

MyClass<T,C>::callFirst MyClass<T,C>::callSecond obj, , .

:

#include <iostream>
#include <string>

double foo(std::string const & s)
{
    return std::stod(s);
}

bool bar(std::string const & s)
{
    return s.size() > 0;
}

struct SomeClass
{
    SomeClass(){};
    double foo(std::string const & s) {
        return ::foo(s);
    }

    bool bar(std::string const & s) const {
        return ::bar(s);
    }
};

int main()
{
    MyClass<std::string> my0{foo,bar};
    std::cout << std::boolalpha;
    std::cout << my0.callFirst("1.11") << std::endl;
    std::cout << my0.callSecond("Hello World") << std::endl;

    MyClass<std::string,SomeClass> my1{&SomeClass::foo,&SomeClass::bar};
    SomeClass thing;
    std::cout << my1.callFirst(thing,"2.22") << std::endl;
    std::cout << my1.callSecond(thing,"Hello World") << std::endl;

    SomeClass const constThing;
    std::cout << my1.callFirst(constThing,"3.33") << std::endl;
    std::cout << my1.callSecond(constThing,"Hello World") << std::endl;
    return 0;
}

, , " ". , , , , . -, , [member] . . .

+2

, , :

template <typename RETURN, typename TYPE, typename CLASS>
struct function_pointer
{ using type_t = RETURN (CLASS::*)(const TYPE &); };

template <typename RETURN, typename TYPE>
struct function_pointer<RETURN, TYPE, std::nullptr_t>
{ using type_t = RETURN (*)(const TYPE &); };

-, . MyClass:

template <typename T, typename CLASS = std::nullptr_t>
class MyClass
{
    using firstFunctionPtr  = typename function_pointer<double, T, CLASS>::type_t;
    using secondFunctionPtr = typename function_pointer<bool, T, CLASS>::type_t;

    // Function pointers as member variables
    firstFunctionPtr _firstFunc;
    secondFunctionPtr _secondFunc;

public:
    inline MyClass(firstFunctionPtr firstFunc, secondFunctionPtr secondFunc) :
        _firstFunc(firstFunc),
        _secondFunc(secondFunc)
    {}

    void call_first(CLASS &c, const T&v) { (c.*_firstFunc)(v); }
    void call_second(CLASS &c, const T&v) { (c.*_secondFunc)(v); }

    void call_first(const T&v) { (_firstFunc)(v); }
    void call_second(const T&v) { (_secondFunc)(v); }
};

call_*, , :

// Some class with the expected function signatures
struct S1
{
    int i = 0;
    double d(const int &) { std::cout << i << ' ' << __PRETTY_FUNCTION__ << '\n'; return{}; }
    bool b(const int &) { std::cout << i << ' ' << __PRETTY_FUNCTION__ << '\n';     return{}; }
};

// Another class with the expected function signatures
struct S2
{
    double d(const int &) { std::cout << __PRETTY_FUNCTION__ << '\n'; return{}; }
    bool b(const int &) { std::cout << __PRETTY_FUNCTION__ << '\n'; return{}; }
};

// Free function with which could have the expected function signature
template <typename R>
R f(const int &) { std::cout << __PRETTY_FUNCTION__ << '\n'; return{}; }

MyClass (S1):

S1 a{1}, b{2};
S2 c, d;
MyClass<int, S1> MCiS1(&S1::d, &S1::b);
MCiS1.call_first(a, 111);  // Prints -> 1 double S1::d(const int&)
MCiS1.call_second(b, 222); // Prints -> 2 bool S1::b(const int&)
MCiS1.call_first(c, 111);  // Error decltype(c) is not S1.
MCiS1.call_second(d, 222); // Error decltype(d) is not S1.

MyClass (S2):

MyClass<int, S2> MCiS2(&S2::d, &S2::b);
MCiS2.call_first(c, 111);  // Prints -> double S2::d(const int&)
MCiS2.call_second(d, 222); // Prints -> bool S2::b(const int&)
MCiS2.call_first(a, 111);  // Error decltype(c) is not S2.
MCiS2.call_second(b, 222); // Error decltype(d) is not S2.

MyClass :

MyClass<int> MCi(f<double>, f<bool>);
MCi.call_first(111);  // Prints -> R f(const int&) [with R = double]
MCi.call_second(222); // Prints -> R f(const int&) [with R = bool]

.

+1

All you have to do is bindinstantiate an object for a member function pointer as the first argument.

struct foo {
    float bar1(const type &var);
    bool bar2(const type &var);
};
foo my_foo;
auto f1 = std::bind(&foo::bar1, my_foo, _1);
auto f2 = std::bind(&foo::bar2, my_foo, _1);
MyClass<type> my_obj(f1, f2);
0
source

Source: https://habr.com/ru/post/1669490/


All Articles