OVH Cloud OVH Cloud

[newbie] curlpp functor

14 réponses
Avatar
none
Bonjour,

Je débute en C++. J'essaye d'écrire un petit programme utilisant CulrPP
et j'ai un probleme avec la classe cURLpp::Types::WriteFunctionFunctor

je la définit comme suit
cURLpp::Types::WriteFunctionFunctor functor(WriteMemoryCallback);

et la fonction WriteMemoryCallback :
size_t WriteMemoryCallback(char* ptr, size_t size, size_t nmemb) {
string strTmp(ptr,size);
buffer += strTmp;
return size*nmemb;
};

Ca fonctionne très bien tant que WriteMemoryCallback est une simple
fonction. Par contre, si je l'encapsule dans une classe, GCC me renvoie :
g++ -Wall -O2 -I/usr/include -c ButineurVirtuel.cpp -o
obj/Release/ButineurVirtuel.o
ButineurVirtuel.cpp: In member function «std::string
ButineurVirtuel::load(std::string)»:
ButineurVirtuel.cpp:22: erreur: no matching function for call to
«utilspp::Functor<unsigned int, utilspp::tl::TypeList<char*,
utilspp::tl::TypeList<unsigned int, utilspp::tl::TypeList<unsigned int,
utilspp::NullType> > > >::Functor(<unknown type>)»
/usr/local/include/utilspp/functor/Functor.inl:29: note: candidats sont:
utilspp::Functor<R, TList>::Functor(Fun) [with Fun = size_t
(ButineurVirtuel::*)(char*, size_t, size_t), R = unsigned int, TList =
utilspp::tl::TypeList<char*, utilspp::tl::TypeList<unsigned int,
utilspp::tl::TypeList<unsigned int, utilspp::NullType> > >]
/usr/local/include/utilspp/functor/Functor.inl:40: note:
utilspp::Functor<R, TList>::Functor(const utilspp::Functor<R, TList>&)
[with R = unsigned int, TList = utilspp::tl::TypeList<char*,
utilspp::tl::TypeList<unsigned int, utilspp::tl::TypeList<unsigned int,
utilspp::NullType> > >]
Process terminated with status 1 (0 minutes, 7 seconds)
3 errors, 0 warnings

D'avance merci,
TSalm




Les codes complets: Le premier listing fonctionne, l'autre non:
=========================DEBUT=============================
#include "main.h"
#include <curlpp/cURLpp.hpp>
#include <curlpp/Easy.hpp>
#include <curlpp/Options.hpp>
#include <curlpp/Exception.hpp>

#define MESS(x) std::cout << x << std::endl

using namespace std;
using namespace cURLpp;

#define MAX_FILE_LENGTH 20000

std::string Buffer;

// Muss statisch sein, sonst schlägt das linken fehl
size_t WriteMemoryCallback(char* ptr, size_t size, size_t nmemb)
{
Buffer += ptr;
return size*nmemb;
};


void print()
{
std::cout << "Length: " << std::endl << Buffer.length() << std::endl;
std::cout << "Content: " << std::endl << Buffer << std::endl;
}


int main(int argc, char *argv[])
{
if(argc != 2) {
std::cerr << "Example 05: Wrong number of arguments" << std::endl
<< "Example 05: Usage: example05 url"
<< std::endl;
return EXIT_FAILURE;
}
char *url = argv[1];

try {
cURLpp::Cleanup cleaner;
cURLpp::Easy request;

// Das writer-Callback setzten, damit
// cURL in einen std::string schreibt
cURLpp::Types::WriteFunctionFunctor functor(WriteMemoryCallback);
cURLpp::Options::WriteFunction *test = new
cURLpp::Options::WriteFunction(functor);
request.setOpt(test);

// Die URL setzten, die emfangen werden soll
request.setOpt(new cURLpp::Options::Url(url));
request.setOpt(new cURLpp::Options::Verbose(false));
request.perform();

//print();
}
catch ( cURLpp::LogicError & e ) {
std::cout << e.what() << std::endl;
}
catch ( cURLpp::RuntimeError & e ) {
std::cout << e.what() << std::endl;
}
}
=========================FIN=============================


=========================DEBUT(ne fonctionne pas)========
#include <iostream>
#include <string>

#include <curlpp/cURLpp.hpp>
#include <curlpp/Easy.hpp>
#include <curlpp/Options.hpp>
#include <curlpp/Exception.hpp>


class ButineurVirtuel {
private:
std::string buffer;

public:
ButineurVirtuel();

std::string load(std::string url);

~ButineurVirtuel();

private:
size_t WriteMemoryCallback(char*, size_t , size_t );
cURLpp::Cleanup cleaner;
cURLpp::Easy request;

};


using namespace std;

// constructeur
ButineurVirtuel::ButineurVirtuel() {
buffer = "";
};

//// fonction interne
size_t ButineurVirtuel::WriteMemoryCallback(char* ptr, size_t size,
size_t nmemb) {
string strTmp(ptr,size);
buffer += strTmp;
return size*nmemb;
};

// charge la page :
std::string ButineurVirtuel::load(std::string url) {
buffer = "";


cURLpp::Types::WriteFunctionFunctor functor(WriteMemoryCallback);
cURLpp::Options::WriteFunction *test = new
cURLpp::Options::WriteFunction(functor);
request.setOpt(test);

request.setOpt(new cURLpp::Options::Url(url));
request.setOpt(new cURLpp::Options::Verbose(false));
request.perform();

//delete test;

return buffer;
};

// destructeur :
ButineurVirtuel::~ButineurVirtuel() {}


int main() {
cout << "hello" << endl;
};

=========================FIN=============================

4 réponses

1 2
Avatar
Sylvain
James Kanze wrote on 07/10/2006 18:25:

en effet, "l'encapsulation" dans une classe change la visibilité.


None seulement la visibilité. Une fonction membre non statique a
un paramètre de plus, le pointeur this. Et il faut l'appeler
avec une syntaxe différente, avec un object.


on pouvait supposer que 'none' sait ce qu'est une méthode d'instance vs
de classe.

une callback doit être static.


Typiquement, il faut aussi qu'elle soit « extern "C" », ce qui
exclut des fonctions membres statiques aussi. Il faut qu'elle
soit globale.


pourquoi "typiquement" ?
a) le pb n'est pas posé ici comme lié à un déploiement par librairies
(ok, le contraire (application monolithique) n'est pas affirmé)
b) avec, par exemple, les extensions MS, je peux importer la définition:

class __declspec(dllimport) ButineurVirtuel {
public:
static size_t WriteMemoryCallback(char*, size_t , size_t );
};

et utiliser un ButineurVirtuel::WriteMemoryCallback(...) correctement
manglé (décoré); gcc ne sait pas publier une classe ? (j'aurais pensé
que comme pour les globales, tout est exporté).

Sylvain.


Avatar
kanze
Sylvain wrote:
James Kanze wrote on 07/10/2006 18:25:

en effet, "l'encapsulation" dans une classe change la visibilité.


None seulement la visibilité. Une fonction membre non
statique a un paramètre de plus, le pointeur this. Et il
faut l'appeler avec une syntaxe différente, avec un object.


on pouvait supposer que 'none' sait ce qu'est une méthode
d'instance vs de classe.


Tout à fait. Et qu'il sait même quelle classe, et qu'il en a une
instance.

Arrivé là, on peut dire qu'on a une interface C++, et non une
interface C. Et dans une interface C++, c'est peut probable
qu'on démande l'adresse d'une fonction ; on spécifie une classe
abstraite, avec une fonction virtuelle qu'on appelle.

une callback doit être static.


Typiquement, il faut aussi qu'elle soit « extern "C" », ce qui
exclut des fonctions membres statiques aussi. Il faut qu'elle
soit globale.


pourquoi "typiquement" ?


Parce que la plupart des API sont définies en termes de C. Et
celle qui sont définies en termes de C++ ne prenent pas de
pointeurs à des fonctions, parce qu'un pointeur à une classe
abstraite résoud le problème d'une façon bien meilleur.

a) le pb n'est pas posé ici comme lié à un déploiement par librai ries
(ok, le contraire (application monolithique) n'est pas affirmé)
b) avec, par exemple, les extensions MS, je peux importer la définition:

class __declspec(dllimport) ButineurVirtuel {
public:
static size_t WriteMemoryCallback(char*, size_t , size_t );
};

et utiliser un ButineurVirtuel::WriteMemoryCallback(...)
correctement manglé (décoré); gcc ne sait pas publier une
classe ? (j'aurais pensé que comme pour les globales, tout est
exporté).


Je ne comprends rien de tout celà. Ce n'est pas du C++.

C'est certain qu'une implémentation peut offrir des extensions
pour supporter différents cas. Si on se sert d'une bibliothèque
qui exige l'utilisation des extensions, il faut y passer. Mais
c'est un cas un peu exceptionnel, ou au moins, je l'espère ; du
moment qu'on se sert des telles extensions, on est coincé, on
dépend entièrement de leur fournisseur.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Avatar
Sylvain
kanze wrote on 11/10/2006 09:36:

[...] Et dans une interface C++, c'est peut probable
qu'on demande l'adresse d'une fonction ; on spécifie une classe
abstraite, avec une fonction virtuelle qu'on appelle.


je privilégie tjrs les modèles basés sur un polymorphisme ... mais ce
n'est pas l'unique solution et il arrive que l'on préfère une autre
approche.

c'est, IHMO, le cas, lorsqu'une "classe container" doit appliquer des
traitements (sort, for each, first that, ...) sur les éléments, on peut
alors souhaiter définir ces traitements comme static de la classe
élement plutôt que comme globales.

soit, le tri peut se faire via un "int T.relativeOrder(T& other)" d'une
interface sortable idoine; soit, les itérations peuvent être autant de
méthodes du container (chacune invoquant une virtuelle donnée);
toutefois on peut préférer ne pas (ou être empêcher de) définir toutes
ces virtuelles mais plutôt une callback static quand il y a lieu.

Parce que la plupart des API sont définies en termes de C. Et
celle qui sont définies en termes de C++ ne prenent pas de
pointeurs à des fonctions, parce qu'un pointeur à une classe
abstraite résoud le problème d'une façon bien meilleur.


c'est plus ou moins le même point, non ?
je suis d'accord que la façon est "meilleure" d'un point de vue
""académique"", elle peut être un peu lourde en pratique.

C'est certain qu'une implémentation peut offrir des extensions
pour supporter différents cas. Si on se sert d'une bibliothèque
qui exige l'utilisation des extensions, il faut y passer. Mais
c'est un cas un peu exceptionnel, ou au moins, je l'espère ; du
moment qu'on se sert des telles extensions, on est coincé, on
dépend entièrement de leur fournisseur.


l'exemple que j'ai donné adressait le problème d'une static (non
globale) dans une librairie *externe* - c'est un cas qui ne me parait
pas fréquent voire pas judicieux.

Sylvain.

Avatar
James Kanze
Manuel Zaccaria wrote:
"kanze" a écrit:


[...]
Mieux, je ne sais pas. Mais celle de Boost a quelques problèmes
sérieux, comme le fait qu'une exception non-catchée puisse
rendre un thread détaché. Elle ne permet pas non plus la
propagation d'une exception à travers un join.


Le mécanisme RTTI est malheureusement insuffisant pour propager
une exception d'un thread à un autre (j'ai essayé... j'ai peut-être
raté un truc, BTW).


Si c'est toi qui gère l'hièrarchie des exceptions, c'est
faisable, au moyen d'un peu de travail, mais ce n'est pas
évident. Si ce n'est pas toi qui la gère, en revanche, il n'y a
pas de moyen.

Si seulement le C++ supportait l'introspection, ça résoudrait
bien des problèmes, surtout pour la sérialisation.


J'ai mes doutes en ce qui concerne la sérialisation. Ça n'aide
que peu en Java, malgré ce qu'on dit. Mais c'est vrai que pour
la transmission des exceptions, elle serait bien utile.

Note que les mechanismes nécessaires sont au moins en partie
présente, parce que nécessaire de toute façon pour la gestion
des exceptions.

--
James Kanze Gabi Software email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


1 2