Forum: PC-Programmierung [c++] optinales funktor/funktionspointer argument


von Vlad T. (vlad_tepesch)


Lesenswert?

Hi, ich habe eine Template Klasse mit einer Memberfunktion Funktion, die 
als optionalen Parameter einen Funktor oder Funtionszeiger haben soll.


ich möchte also hinterher

entweder
process(var)
oder
process(var, Funktor())
oder
process(var, &funktion)
 aufrufen können

wie hat das auszusehen?
Bisher hab ich das getrennt implementiert:
1
#include <iostream>
2
#include <string>
3
using namespace std;
4
5
template <class A, class B>
6
class C
7
{
8
public:
9
10
  static string  printNothing()   {return "";}
11
12
  template < typename ProcessFunctorType>
13
  void process(int i, ProcessFunctorType& pfunc)
14
  {
15
    cout << i << " "<<pfunc()<<endl;
16
  }
17
18
  // diese funktion hätte ich gerne weg, so dass standardmäßig die 
19
  // andere mit printNothing aufgerufen wird.
20
  void process(int i){
21
    cout << i << " "<<endl;
22
  }
23
  
24
  A a;
25
  B b;
26
};
27
28
static string  printSomething() {return "foo";}
29
30
int main()
31
{
32
  C<int, int> c;
33
  c.process(1);
34
  c.process(2, C<int, int>::printNothing);
35
  c.process(3, printSomething);
36
37
}
Da ich aber noch einen weiteren funktor hinzufügen möchte, explodiert 
die Variantenanzahl und ich würde das gerne vereinheitlichen

Hat jemand eine Idee?

hier zum direkten ausprobieren:
http://codepad.org/Pkh944rz

Gruß
Vlad

von Rolf (Gast)


Lesenswert?

Ich habe nicht so viel Ahnung und habe es auch nicht ausprobiert, aber 
vielleicht so:
1
template < typename ProcessFunctorType>
2
  void process(int i, ProcessFunctorType& pfunc = NULL)
3
  {
4
    cout << i << " "<<pfunc()<<endl;
5
  }

von Rolf (Gast)


Lesenswert?

Oder vielleicht so:
1
template < typename ProcessFunctorType>
2
  void process(int i, ProcessFunctorType& pfunc = printNothing )
3
  {
4
    cout << i << " "<<pfunc()<<endl;
5
  }

von Rolf (Gast)


Lesenswert?


von Vlad T. (vlad_tepesch)


Lesenswert?

Rolf schrieb:
> http://ladedu.com/cpp/src_html/standard

was will uns der poster damit sagen?

Rolf schrieb:
> Ich habe nicht so viel Ahnung und habe es auch nicht ausprobiert, aber
> vielleicht so:

die andern sachen gehen natürlich auch nicht.

weder darf man einer referenz NULL zuweisen, noch wird der defaultwert 
bei templates beachtet

von Rolf (Gast)


Lesenswert?

hier Problem auch nicht gelöst:
http://www.cplusplus.com/forum/general/7102/

Vielleicht bekommst du dadurch ja neue Ideen. Ich habe nicht genug 
Ahnung, um weiter zu helfen, war nur gut gemeint.

von ich (Gast)


Lesenswert?

Vlad Tepesch schrieb:
> Rolf schrieb:
>> http://ladedu.com/cpp/src_html/standard
>
> was will uns der poster damit sagen?
>
> Rolf schrieb:
>> Ich habe nicht so viel Ahnung und habe es auch nicht ausprobiert, aber
>> vielleicht so:
>
> die andern sachen gehen natürlich auch nicht.
>
> weder darf man einer referenz NULL zuweisen, noch wird der defaultwert
> bei templates beachtet

Das geht prinzipiell schon, es muss allerdings eher so aussehen:
1
#include <iostream>
2
#include <string>
3
using namespace std;
4
5
static string  printSomething() {return "foo";}
6
7
8
template <class A, class B>
9
class C
10
{
11
public:
12
13
  static string  printNothing()   {return "";}
14
15
  template < typename ProcessFunctorType =  string () >
16
  void process(int i, ProcessFunctorType &pfunc = printNothing)
17
  {
18
      cout << i << " " <<pfunc()<<endl;
19
  }
20
21
22
//  void process(int i){
23
//    cout << i << " "<<endl;
24
//  }
25
26
  A a;
27
  B b;
28
};

Ausgabe:
1
1 
2
2 
3
3 foo

Default template Argumente bei Funktionstemplates gibt es allerdings 
erst ab C++11.

(kompiliert mit gcc 4.6 und -std=c++0x)

von Vlad T. (vlad_tepesch)


Lesenswert?

ich schrieb:
> Das geht prinzipiell schon, es muss allerdings eher so aussehen:
hmm - den default  template parameter verstehe ich nicht.
müsste es nicht irgendwie "string (*)()" oder so heißen, weil ja der 
Templateparameter ein Funktionspointer ist.

kompiliert er denn auch noch sowas:
1
class TestFunctor{
2
public:
3
  TestFunctor(const string& s)
4
  : m_s(s)
5
  {}
6
7
  string operator()(){
8
    return m_s;
9
  }
10
11
private:
12
  string m_s;
13
};
14
15
///...
16
17
  TestFunctor tf("hallo");
18
  c.process(4, tf );

könnte mir vorstellen, dass es hier Probleme gibt, da der Typ das 
Defaultarguments ( string (*)() ) nicht zum Templatetyp (TestFunctor) 
passt.

kannst du das mal durch deinen Compiler jagen?

Das Codepad und mein MSVC können das nicht

von Vlad T. (vlad_tepesch)


Lesenswert?

was mir grad noch einfällt (eigentlich das naheliegendste):

in den überladenen Varianten jeweils die templatevariante rufen
1
  void process(int i)
2
  {
3
    process(i, printNothing);
4
  }

von Rolf (Gast)


Lesenswert?

Vlad Tepesch schrieb:
> kannst du das mal durch deinen Compiler jagen?

[23:07:22] <rolf@SL510-Fedora.fritz.box> ~/cpp ((Linux 
3.5.2-1.fc17.x86_64))
1 processes #55 $ g++ -std=c++11 beispiel2.cpp -o beispiel2
[23:09:49] <rolf@SL510-Fedora.fritz.box> ~/cpp ((Linux 
3.5.2-1.fc17.x86_64))
1 processes #56 $ ./beispiel2
1
2
3 foo
4 hallo


macht er ohne zu meckern.

Starte mal eine Linux-Live-Session entweder vom USB-Stick oder von einer 
CD, dann kannst Du das auch selber testen.

von ich (Gast)


Lesenswert?

Vlad Tepesch schrieb:
> hmm - den default  template parameter verstehe ich nicht.
> müsste es nicht irgendwie "string (*)()" oder so heißen, weil ja der
> Templateparameter ein Funktionspointer ist.

Da du pfunc als Referenz übergibst, muss der default template Parameter 
entweder "string ()" oder "string (&)()" sein. Mit "string (*)()" gibt 
es die Fehlermeldung:
1
In member function 'void C<A, B>::process(int, ProcessFunctorType&) [with ProcessFunctorType = std::basic_string<char> (*)(), A = int, B = int]':
2
default argument for parameter of type 'std::basic_string<char> (*&)()' has type 'std::string() {aka std::basic_string<char>()}'

Also:
1
// entweder so
2
  template < typename ProcessFunctorType =  string () >
3
  void process(int i, ProcessFunctorType &pfunc = printNothing)
4
5
// oder so
6
  template < typename ProcessFunctorType =  string (&)() >
7
  void process(int i, ProcessFunctorType &pfunc = printNothing)
8
9
// oder als Funktionszeiger
10
  template < typename ProcessFunctorType =  string (*)() >
11
  void process(int i, ProcessFunctorType pfunc = printNothing)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.