tr1 :: mem_fn und tr1 :: bind: auf const-Korrektheit und Überlastung
-
10-07-2019 - |
Frage
Was ist mit 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;
}
Der Versuch, es mit g ++ zu kompilieren - 4.3, scheint es, dass cv -qualifier ladenen Funktionen verwirren sowohl tr1::mem_fn<>
und tr1::bind<>
und es kommt folgende Fehlermeldung:
no matching function for call to ‘bind(<unresolved overloaded function type>,...
Stattdessen wird der folgende Code-Schnipsel kompiliert aber scheint die const-Korrektheit zu brechen :
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);
Jeder Hinweis?
Lösung
Das Nachschlagen zu einem Zeitpunkt durchgeführt, wenn die Konstantheit von this
ist nicht bekannt. Sie müssen es nur einen Hinweis über Gießen geben. Versuchen Sie folgendes:
typedef void (abc::*fptr)(int) const; // or remove const
std::tr1::bind((fptr)&abc::hello, x , _1)(a);
Sie können auch hier feststellen, dass die const
Entfernung noch funktioniert. Dies liegt daran, dass man x sollte durch Zeiger Passing (weil das erste Argument für eine C ++ Elementfunktion, der implizite this
Parameter ist immer ein Zeiger). Versuchen Sie stattdessen:
typedef void (abc::*fptr)(int) const; // won't compile without const (good!)
std::tr1::bind((fptr)&abc::hello, &x , _1)(a);
Wie unten während innerhalb von mir entdeckt, wenn Sie die &
weglassen, wie Sie ursprünglich tat, werden Sie x werden vorbei Wert , das ist in der Regel nicht, was Sie wollen (obwohl es wenig praktikabel macht Unterschied in Ihrem speziellen Beispiel). Dies scheint tatsächlich wie ein unglücklicher pitfall für bind
.
Andere Tipps
Diese Frage beantwortet wurde, aber ich finde den besten Weg, um eine Überlastung zu spezifizieren mit binden sie auf der Vorlage angeben, lautet:
std::tr1::bind<void(foo::*)(int)>(&foo::bar);
Diese Methode ist ebenso explizit, aber kürzer als Gussteil (mit static_cast
sowieso. Aber es ist sauberer als das C-Cast, die gleich lang ist.
Wie John vorgeschlagen, die in diesen Schnipsel entstanden Probleme sind die folgenden:
- Beim Passieren eines Mitglied-Funktion-Zeiger ist es notwendig, seine Unterschrift zu geben (wenn überlastet)
-
bind()
werden gebenen Argumente von Wert.
Das erste Problem ist durch Gießen des Mitgliedsfunktionszeigers vorgesehen gelöst zu binden:
std::tr1::bind(static_cast< void(abc::*)(int) const >(&abc::hello), x, _1)(a);
Die zweite kann, indem man das aufrufbare Objekt nach Adresse gelöst werden (als John vorgeschlagen) oder mittels TR1 reference_wrapper<>
- sonst wird es von Wert übergeben werden, so dass die const-Korrektheit bricht Halluzination .
x ein aufrufbare Objekt Gegeben:
std::tr1::bind( std::tr1::ref(x) , _1)(a);
bind()
wird a
auf die richtige operator()
gemäß der x weiterleiten Konstantheit .