Как & quot; бросить & quot; функция с двумя аргументами в функцию с одним аргументом?

В Matlab можно написать:

S = @(x,y) x^2+y^2-1
G = @(x) S(x,1);

Если у меня есть функция, ожидающая функцию с одним аргументом, я могу сделать выше. Как я могу сделать это в C / C ++?

У меня есть библиотечная функция (из библиотеки CGAL), которая ожидает в качестве аргумента функцию, которая сама имеет только один аргумент. В идеале у меня есть класс (SphericalHarmonics) и я хотел бы иметь функцию-член, которая принимает один аргумент. Так что я:

FT SphericalHarmonics::distFunction(Point_3 p)

(Обратите внимание, что FT тип похож на double) но конечно когда попробую

SphericalHarmonics *sh = new SphericalHarmonics(1);
Surface_3 surface(sh->distFunction, Sphere(ORIGIN,2.));

this также рассматривается как аргумент, мой distFunction Функция является функцией с двумя аргументами, и выдается ошибка.

Обратите внимание, что это может быть решено с помощью глобальных переменных, т.е.

SphericalHarmonics *sh;
FT dist_function(Point_3 p) {
return sh->distFunction(p);
}

main() {
sh = new SphericalHarmonics(1);
Surface_3 surface(dist_function);
}

Тем не менее, это действительно не идеально. Я хотел бы сделать это без глобальных переменных, так как было бы гораздо лучше иметь функцию класса, которая легко интегрируется с библиотекой CGAL.

Заранее спасибо!

[ОБНОВЛЕНО]

@ Энди-Prowl: я попробовал ваш std::bind а также lambda решения, но все же, кажется, сталкиваются с ошибками в отношении количества аргументов.

Когда в mainЯ использую код:

SphericalHarmonics *sh = new SphericalHarmonics(cInit, numL, symm);
auto fxn = std::bind(&SphericalHarmonics::distFunction, sh, std::placeholders::_1);
Surface_3 surface(fxn, Sphere_3(ORIGIN,2.));

Я получаю ошибки:

~/lib/basisfunctions/SphericalHarmonics2/mesh_an_implicit_function.cpp:62:48:
error: no matching function for call to
‘CGAL::Implicit_surface_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>,
double (*)
(CGAL::Point_3<CGAL::Epick>)>::Implicit_surface_3(std::_Bind<std::_Mem_fn
<double (SphericalHarmonics::*)(CGAL::Point_3<CGAL::Epick>)>
(SphericalHarmonics*, std::_Placeholder<1>)>&, Sphere_3)’

а также

~/CGAL-4.1/include/CGAL/Implicit_surface_3.h:50:5: note:   no known conversion
for argument 1 from ‘std::_Bind<std::_Mem_fn<double (SphericalHarmonics::*)
(CGAL::Point_3<CGAL::Epick>)>(SphericalHarmonics*, std::_Placeholder<1>)>’ to
‘CGAL::Implicit_surface_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>,
double (*)(CGAL::Point_3<CGAL::Epick>)>::Function
{aka double (*)(CGAL::Point_3<CGAL::Epick>)}’

а также

~/CGAL-4.1/include/CGAL/Implicit_surface_3.h:34:9: note:
candidate expects 1 argument, 2 provided

[ОБНОВЛЕНО]

Теперь мне ясно, что мне нужна функция, которую можно преобразовать в указатель функции (т.е. surface требуется аргумент указателя на функцию). Это исключает std::bind вариант. Более того, оказывается, что лямбда не может быть преобразована в указатель на функцию, если она захватывает переменные (без захвата против захвата лямбд). Таким образом, я думаю, что ответ Энди-Проул ниже является в целом правильным ответом на этот вопрос, хотя мне нужно будет найти другой обходной путь.

5

Решение

ОПЦИЯ 1:

В случае, если ваша функция-член не может неявно работать с экземпляром вашего класса (и, следовательно, не нужно получать this указатель), вы можете сделать это static:

class SphericalHarmonics
{
...
static double distFunction(Point p);
...
};

double SphericalHarmonics::distFunction(Point p)
{
...
}

Теперь ваша функция будет иметь единственный аргумент:

surface(SphericalHarmonics::distFunction);

ВАРИАНТ 2:

В противном случае вы можете использовать std::bind() карри функцию-член distFunction и исправьте его первый, неявный аргумент (если вы не работаете с компилятором C ++ 11, вы можете использовать эквивалентный boost::bind() от Boost.Bind библиотека):

#include <functional>

SphericalHarmonics *sh = new SphericalHarmonics(1);
auto fxn = std::bind(&SphericalHarmonics::distFunction, sh, _1);
surface(fxn);

ВАРИАНТ 3:

В качестве альтернативы, в C ++ 11 лямбда может сделать эту работу:

SphericalHarmonics *sh = new SphericalHarmonics(1);
auto fxn = [=] (double d) { return sh->distFunction(d); }
5

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

использование станд :: привязывать или же повышение :: BIND :

#include <functional>

SphericalHarmonics *sh = new SphericalHarmonics(1);
surface(std::bind(&SphericalHarmonics::distFunction, sh, _1));
5

В конкретном случае борьбы с шаблонами CGAL Surface_3 учебный класс. Вы, вероятно, используете что-то вроде этого (из их примера) для определения Surface_3 тип:

typedef CGAL::Surface_mesh_default_triangulation_3 Tr;
// c2t3
typedef CGAL::Complex_2_in_triangulation_3<Tr> C2t3;
typedef Tr::Geom_traits GT;
typedef GT::Sphere_3 Sphere_3;
typedef GT::Point_3 Point_3;
typedef GT::FT FT;
typedef FT (*Function)(Point_3);
typedef CGAL::Implicit_surface_3<GT, Function> Surface_3;

Это вводящий в заблуждение потому что кажется, что классы изоповерхностей CGAL могут иметь дело только с указателями на функции (в отличие от std::function так далее.). Но проблема только в том, что мы просто определил это так. Просто определить Surface_3 использовать std::function<FT (Point_3)> в качестве аргумента шаблона и тому std::bind и лямбды из Энди Prowl ответ будет работать просто отлично

...
typedef std::function<FT (Point_3)> Function;
typedef CGAL::Implicit_surface_3<GT, Function> Surface_3;
1
По вопросам рекламы [email protected]