C ++ 11 — Как реализовать простейшую C ++ обертку для вызываемого объекта?

Я хочу реализовать класс FuncWrapper, который ведет себя так, как показано ниже, но я считаю, что это не так просто, как ожидалось.

int OrdinaryFunction(int n)
{
return n;
}

struct Functor
{
int operator ()(int n)
{
return n;
}
};

int main()
{
FuncWrapper<int(int)> f1(OrdinaryFunction);
cout << f1(1); // output 1;

Functor functor;
FuncWrapper<int(int)> f2(functor);
cout << f2(2); // output 2;

return 0;
}

Мой вопрос: как реализовать класс FuncWrapper в PURE C ++ (т.е. без STL) для компиляции кода?

Я частично показывал FuncWrapper, показанный ниже:

template<class T>
class FuncWrapper;

template<class ReturnType, class Parameter1>
class FuncWrapper<ReturnType(Parameter1)>
{
public:
typedef ReturnType (*FunctionPtr)(Parameter1);

template<class Functor>
FuncWrapper(Functor fn)
{
// ???
}

FuncWrapper(FunctionPtr fn)
: fn(fn)
{}

ReturnType operator ()(Parameter1 p1)
{
return this->fn(p1);
}

private:
FunctionPtr fn;
};

4

Решение

Хорошо, вы можете подумать, что делать то, что вы пытаетесь, просто, но это очень сложно.

В вашем случае вы хотите иметь возможность добавлять функтор и фактическую функцию, и это усложняет ситуацию. В конце концов, если ваш класс переносит конструктор в функтор Functor, где вы будете хранить объект?

Один из методов, используемый boost в его классе общего указателя для хранения средства удаления, заключается в том, чтобы фактически иметь базовый класс и производный класс. Ваш конструктор создаст объект (с новым), который является производным от базового класса, а затем вы используете полиморфизм для вызова.

boost использует все виды умных техник в своих библиотеках функций и binder / mpl, но сейчас я бы посоветовал вам использовать эту.

Если вы действительно против использования boost или любого другого общего указателя, вам придется управлять памятью для этого объекта. (Раздражает, потому что вы хотите, чтобы ваш внешний класс был копируемым и назначаемым).

Я собираюсь сделать это простым и сказать, что я могу использовать shared_ptr. Я также собираюсь упростить подпись на данный момент.

Как набросок …

template< typename R, typename P > class FunctorBase
{
public:
virtual ~FunctorBase() {}
virtual R call(P p) = 0;
};

template< typename R, typename P > class FunctionWrapper
{
shared_ptr< FunctorBase< R, P > > impl;
public:
template< typename F > // a functor
FunctionWrapper( Functor f )
{
// create appropriate impl for functors
}

FunctionWrapper( (R (func*)(P) )
{
// create appropriate impl for functions
}

R operator()( P p )
{
return impl->call(p);
}
};

Ваша реализация функтора может быть что-то вроде:

template< typename R, typename P, typename F >
class FunctorImpl : public FunctorBase< R, P >
{
F f;

public:
FunctorImpl( F fparam ) : f( fparam )
{
}

R call( P p )
{
return f( p );
}
};

Итак, теперь вы видите, где вы можете хранить функтор ..

3

Другие решения

Просто добавьте в ваш функтор конструктор, который принимает указатель на функцию (с нужной сигнатурой функции). Сохраните указатель в функторе и выполните указанную функцию из оператора ().

Если я вас правильно понимаю, вам нужна обертка, которая будет представлять функциональное поведение как для функторов, так и для функций. Храните указатель на функтор в вашей оболочке вместо указателя на функцию. Конструктор с функтором в качестве параметра будет хранить функтор внутри. Конструктор с параметром func создаст функтор (как я написал в ответе) и сохранит его внутри.

0

По вопросам рекламы [email protected]