boost::function "is not a valid type for a template constant parameter"



  • Hi!
    Ich moechte eine bestimmte Art von Functor als Template uebergeben. Als ich das mit Funktionspointern geloest hatte, war das auch kein Problem. Da ich allerdings neben Funktionspointern auch structs mit ueberladenem operator() als Functor uebergeben moechte, wollte ich boost::function verwenden. Dabei meint der GCC allerdings, das das nicht "a valid type for a template constant parameter" sei.

    Minimalbeispiel:

    #include <iostream>
    #include <boost/function.hpp>
    #include <boost/array.hpp>
    
    using namespace std;
    using namespace boost;
    
    typedef array<double, 5> Array;
    //typedef function < double (Array const&) > Function;
    typedef double (*Function)(Array const&); // <== DAS HIER WUERDE FUNKTIONIEREN
    
    template<Function f>
    double apply(Array const& a)
    {
    	return f(a);
    }
    
    struct mult
    {
    	double operator()(Array const& a)
    	{
    		double p = 1;
    		for (unsigned i = 0; i < a.size(); ++i)
    			p *= a[i];
    		return p;
    	}
    };
    
    double sum(Array const& a)
    {
    	double sum  = 0;
    	for (unsigned i = 0; i < a.size(); ++i)
    		sum += a[i];
    	return sum;
    }
    
    int main()
    {
    	Array a = {{1, 2, 3, 4, 5}};
    	cout << "sum:  " << apply<sum>(a) << endl;
    	cout << "prod: " << apply<mult()>(a) << endl; // <== DAS GEHT NICHT
    	return 0;
    }
    

    Was kann ich tun? Ich moechte neben Funktionspointern eben auch Klassen-Functors verwenden.



  • Mit mult() in apply<mult()>(a) erzeugst du ja eine Instanz, du brauchst ja nen Typ (also nur mult ). Dürfte aber auch nicht klappen durch deine Templateparameter-Einschränkung. Wie wär's so?:

    template<typename Func>
    double apply( Array const& a, Func func )
    {
        return func( a );
    }
    
    apply( a, &sum );
    apply( a, mult() );
    

    Ansonsten würde ich std::tr1::function bzw std::function aus <functional> vorziehen.



  • Badestrand_ schrieb:

    Wie wär's so?:
    [...]

    Da der echte Code mehr Parameter hat wuerde das die Funktion extrem aufblaehen, das moecht ich vermeiden. Ausserdem will ich sichergehen dass die Funktionen geinlined werden, da es sich um den absolut performancekritischten Teil der Applikation handelt.

    Ansonsten würde ich std::tr1::function bzw std::function aus <functional> vorziehen.

    std::tr1::function ist doch boost::function, damit gewinn ich dann also auch nix 😕



  • Blue-Tiger schrieb:

    Ausserdem will ich sichergehen dass die Funktionen geinlined werden, da es sich um den absolut performancekritischten Teil der Applikation handelt.

    Du kannst auf jeden Fall keine Instanz als Template-Paramter übergeben, da gehen nur Typen oder Compile-Time konstante "Werte".
    Funktoren willst du doch sicherlich auch nutzen, um State zu haben; dazu musst du eine konkrete Instanz übergeben und das klappt eben nur mit "normalem" Parameter. Mit Verzicht auf boost::function dürfte das für den Compiler IMO auch recht gut optimierbar sein.

    Blue-Tiger schrieb:

    std::tr1::function ist doch boost::function, damit gewinn ich dann also auch nix 😕

    Dann hat man halt die boost-Abhängigkeit nicht. Ist hier jetzt aber natürlich egal.



  • Blue-Tiger schrieb:

    Ich moechte eine bestimmte Art von Functor als Template uebergeben.

    Erster Indikator für ein Missverständnis.

    Blue-Tiger schrieb:

    #include <iostream>
    #include <boost/function.hpp>
    #include <boost/array.hpp>
    
    using namespace std;
    using namespace boost;
    
      typedef array<double, 5> Array;
    //typedef function < double (Array const&) > Function;
      typedef double (*Function)(Array const&); // <== DAS HIER WUERDE FUNKTIONIEREN
    

    Wozu ist "Function" gut?

    template<Function f>
    

    Hier ist f ein nicht-Typ Template-Parameter. Als Nicht-Typ Template-Parameter werden nur integrale Konstanten, Zeiger-Konstanten bzw Referenzen auf Objekte und Funktionen mit externer Bindung erlaubt -- also alles Parameter, welche zur Compile-Zeit bekannt sind. Mit "Function" als alias für function<double(Array const&)> versuchst Du ein Objekt als Template-Parameter zu übergeben. Das funktioniert deswegen also nicht.

    double apply(Array const& a)
    {
    	return f(a);
    }
    
    struct mult
    {
    	double operator()(Array const& a)
    	{
    		double p = 1;
    		for (unsigned i = 0; i < a.size(); ++i)
    			p *= a[i];
    		return p;
    	}
    };
    
    double sum(Array const& a)
    {
    	double sum  = 0;
    	for (unsigned i = 0; i < a.size(); ++i)
    		sum += a[i];
    	return sum;
    }
    
    int main()
    {
    	Array a = {{1, 2, 3, 4, 5}};
    	cout << "sum:  " << apply<sum>(a) << endl;
    	cout << "prod: " << apply<mult()>(a) << endl; // <== DAS GEHT NICHT
    	return 0;
    }
    

    Mach's so:

    template<typename FunctorType>
    double apply(Array const& a, FunctorType f)
    {
    	return f(a);
    }
    
    struct mult
    {
    	double operator()(Array const& a) const // <-- habe const hinzugefügt
    	{
    		double p = 1;
    		for (unsigned i = 0; i < a.size(); ++i)
    			p *= a[i];
    		return p;
    	}
    };
    
    double sum(Array const& a)
    {
    	double sum  = 0;
    	for (unsigned i = 0; i < a.size(); ++i)
    		sum += a[i];
    	return sum;
    }
    
    int main()
    {
    	Array a = {{1, 2, 3, 4, 5}};
    	cout << "sum:  " << apply(a,&sum) << endl;
    	cout << "prod: " << apply(a,mult() << endl;
    }
    

    Ein function<> gibt's hier auch nicht.



  • Alternativ:

    double apply(Array const& x, function<double(Array const&)> f)
    {
      return f(x);
    }
    

    Dazu muss apply kein Template sein. Das ist ja gerade der Witz an function!



  • Thx fuer die Erklaerungen und Tipps 🙂


Anmelden zum Antworten