5 Stimmen

tr1::mem_fn und tr1::bind: über Konst-Korrektheit und Überladung

Was ist an dem folgenden Ausschnitt falsch?

#include <tr1/functional>
#include <functional>
#include <iostream>

using namespace std::tr1::placeholders;

struct abc
{
    typedef void result_type;

    void hello(int)
    { std::cout << __PRETTY_FUNCTION__ << std::endl; }

    void hello(int) const
    { std::cout << __PRETTY_FUNCTION__ << std::endl; }

    abc()
    {}
};

int
main(int argc, char *argv[])
{
    const abc x;
    int a = 1;

    std::tr1::bind(&abc::hello, x , _1)(a);
    return 0;
}

Beim Versuch, es mit g++-4.3 zu kompilieren, scheint es, dass cv -Qualifier überladene Funktionen verwirren beide tr1::mem_fn<> y tr1::bind<> und es wird folgende Fehlermeldung angezeigt:

no matching function for call to ‘bind(<unresolved overloaded function type>,...

Stattdessen kompiliert das folgende Snippet, scheint aber die const-correctness :

struct abc
{
    typedef void result_type;

    void operator()(int)
    { std::cout << __PRETTY_FUNCTION__ << std::endl; }

    void operator()(int) const
    { std::cout << __PRETTY_FUNCTION__ << std::endl; }

    abc()
    {}
};

...

    const abc x;
    int a = 1;
    std::tr1::bind( x , _1)(a);

Haben Sie einen Hinweis?

4voto

John Zwinck Punkte 221200

Das Nachschlagen erfolgt zu einem Zeitpunkt, zu dem die Konstante von this ist nicht bekannt. Sie müssen ihm nur durch einen Wurf einen Hinweis geben. Versuchen Sie dies:

typedef void (abc::*fptr)(int) const; // or remove const
std::tr1::bind((fptr)&abc::hello, x , _1)(a);

Sie werden auch feststellen, dass das Entfernen der const funktioniert immer noch. Das liegt daran, dass Sie x per Zeiger übergeben sollten (weil das erste Argument einer C++-Mitgliedsfunktion, die implizite this Parameter, ist immer ein Zeiger). Versuchen Sie stattdessen dies:

typedef void (abc::*fptr)(int) const; // won't compile without const (good!)
std::tr1::bind((fptr)&abc::hello, &x , _1)(a);

Wie ich in meinen Kommentaren weiter unten festgestellt habe, können Sie die & wie Sie es ursprünglich getan haben, werden Sie vorbeikommen x nach Wert was in der Regel nicht erwünscht ist (auch wenn es in Ihrem speziellen Beispiel kaum einen praktischen Unterschied macht). Dies scheint tatsächlich eine unglückliche Falle zu sein für bind .

1voto

Nicola Bonelli Punkte 7933

Wie John vorschlug, sind die Probleme, die in diesen Schnipseln auftauchen, die folgenden:

  1. Wenn Sie eine member-function-pointer ist es notwendig, seine Signatur anzugeben (falls überladen)
  2. bind() werden Argumente als Wert übergeben.

Das erste Problem wird durch das Casting des Zeigers der Mitgliedsfunktion gelöst, der für bind vorgesehen ist:

    std::tr1::bind(static_cast< void(abc::*)(int) const >(&abc::hello), x, _1)(a);

Das zweite Problem kann gelöst werden, indem man das aufrufbare Objekt per Adresse übergibt (wie John vorschlug), oder mit Hilfe von TR1 reference_wrapper<> -- andernfalls wird er als Wert übergeben, wodurch die Konstante-Korrektheit-Brechung-Halluzination .

Gegeben x ein aufrufbares Objekt:

std::tr1::bind( std::tr1::ref(x) , _1)(a);

bind() wird weitergeleitet a zum richtigen operator() in Übereinstimmung mit dem x constness .

1voto

coppro Punkte 14158

Diese Frage wurde bereits beantwortet, aber ich finde, der beste Weg, eine Überladung mit bind anzugeben, ist, sie in der Vorlage anzugeben:

std::tr1::bind<void(foo::*)(int)>(&foo::bar);

Diese Methode ist genauso eindeutig, aber kürzer als das Casting (mit static_cast sowieso. Aber es ist sauberer als der C-Guss, der die gleiche Länge hat.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X