2013-02-28 12 views
5

w Matlab, można napisać:Jak "rzucić" funkcję dwuargumentową do funkcji jednoargumentowej?

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

Jeśli mam funkcji spodziewa funkcję jednego argumentu, mogę zrobić to powyżej. Jak mogę to zrobić w c/C++?

Mam funkcję biblioteczną (z biblioteki CGAL), która oczekuje jako argument funkcji, która sama ma tylko jeden argument. Idealnie, mam klasy (SphericalHarmonics) i chciałbym mieć funkcję członka, który ma jeden argument. Tak mam:

FT SphericalHarmonics::distFunction(Point_3 p) 

(zauważ, że FT jest rodzajem podobny do double), ale oczywiście, gdy próbuję

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

this jest również traktowane jako argument, mój distFunction funkcja jest dwu- funkcja argumentu i zgłaszany jest błąd.

Zauważ, że to może być rozwiązany z zmienne globalne, tzn

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

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

Jednak jest to naprawdę nie idealny. Chciałbym, aby to zrobić bez zmiennych globalnych, ponieważ byłoby znacznie lepiej móc mieć funkcję klasy, która łatwo integruje się z biblioteką CGAL.

Z góry dziękuję!

[AKTUALIZACJA]

@ Andy-Prowl: Próbowałem swoje rozwiązania std::bind i lambda, ale wciąż wydaje się być uruchomiony do błędów w odniesieniu do liczby argumentów.

Kiedy w main używam kod:

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.)); 

dostaję błędy:

~/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)’ 

i

~/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>)}’ 

i

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

[aktualizacji]

to jest oczywiste, że w potrzebne do funkcji, która może być przekształcona w funkcji wskaźnika (tj surface wymagany argument wskaźnika funkcji). To wyklucza opcję std::bind. Ponadto wydaje się, że lambda nie może zostać przekonwertowana na wskaźnik funkcji, jeśli przechwytuje zmienne (capture-less vs. capturing lambdas). Więc myślę, że odpowiedź Andy-Prowl'a poniżej jest ogólnie poprawną odpowiedzią na to pytanie, chociaż muszę znaleźć inne podejście do pracy.

+3

(I naprawdę nie przeczytać pytanie) wiążą lub lambda? –

+0

Znaczniki wprowadzają w błąd, powinny zawierać matlab/lambda – Dmitry

+0

Czy któreś z tych rozwiązań rzeczywiście działa? Czy nie można użyć binda, aby stać się wskaźnikiem funkcji? –

Odpowiedz

5

OPCJA 1:

W przypadku, gdy funkcja członek nie niejawnie pracować na instancji klasy (a więc nie musi otrzymują this wskaźnik), można dokonać jej static:

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

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

Teraz twoja funkcja będzie skutecznie mieć jeden argument:

surface(SphericalHarmonics::distFunction); 

Opcja 2:

W przeciwnym razie, można użyć std::bind() curry z funkcji członka distFunction i naprawić swój pierwszy, niejawny argument (jeśli ciebie nie działa z C++ 11 kompilatora, można użyć równoważnego boost::bind() z biblioteki Boost.Bind):

#include <functional> 

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

Opcja 3:

Alternatywnie, w C++ 11, lambda mogła wykonać zadanie:

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

Dzięki! Jestem pewien, że to jest poprawne, więc już je zaznaczyłem. Opcja 1 nie jest opcją (chcę pracować na określonych instancjach klasy). Kiedy próbuję opcji 2 lub 3, otrzymuję błędy "error:" fxn "nie określa typu" i "error:" fxn "nie został zadeklarowany w tym zakresie. Próbowałem zarówno 'std :: bind' i' boost :: bind' (includind '' i '') i pojawia się ten sam błąd. Używanie gcc w wersji 4.6.3 na Ubuntu 12.04 – OwenM

+0

@ OwenM: Czy używasz kompilatora C++ 11 z opcją -stre = C++ 0x' lub '-std = C++ 11'? Słowo kluczowe 'auto' wymaga C++ 11. Proponuję również uaktualnienie do GCC 4.7.2, wersja, której używasz jest dość stara. Istnieje również [ta strona internetowa] (http://www.liveworkspace.org), gdzie można skompilować swój kod za pomocą różnych kompilatorów. –

+0

Tak, gcc 4.7.2 z opcją -std = C++ 11 rozwiązało ten problem! – OwenM

5

Zastosowanie std::bind lub boost::bind:

#include <functional> 

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

Masz na myśli sh zamiast tego? – Slava

+0

@Slava Yep, dzięki. – Drax

1

W tym konkretnym przypadku do czynienia z matrycy Surface_3 klasy CGAL użytkownika. Prawdopodobnie używasz coś takiego (od ich przykładem) określenie Surface_3 typ:

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; 

To mylące ponieważ to sprawia, że ​​wydaje się zajęcia isosurface CGAL mogą zajmować się tylko wskaźników funkcji (w przeciwieństwie do std::function itp.). Ale problem polega tylko na tym, że mamy właśnie zdefiniowaliśmy to w ten sposób. Wystarczy zdefiniować Surface_3 używać std::function<FT (Point_3)> jako szablonu argumentu i std::bind i lambdas od Andy Prowl's answer będzie działać dobrze:

... 
typedef std::function<FT (Point_3)> Function; 
typedef CGAL::Implicit_surface_3<GT, Function> Surface_3; 
Powiązane problemy