В 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
вариант. Более того, оказывается, что лямбда не может быть преобразована в указатель на функцию, если она захватывает переменные (без захвата против захвата лямбд). Таким образом, я думаю, что ответ Энди-Проул ниже является в целом правильным ответом на этот вопрос, хотя мне нужно будет найти другой обходной путь.
ОПЦИЯ 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); }
использование станд :: привязывать или же повышение :: BIND :
#include <functional>
SphericalHarmonics *sh = new SphericalHarmonics(1);
surface(std::bind(&SphericalHarmonics::distFunction, sh, _1));
В конкретном случае борьбы с шаблонами 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;