Ich würde gerne Komposition und schreiben gute Weiterleitungsmethoden für jede mögliche Überladung (noexcept, const, flüchtige) mit C++ Fähigkeiten.Method forwarding mit Zusammensetzung statt Vererbung (mit C++ - Traits)
Die Idee ist, Eigenschaften zu verwenden, um zu bestimmen, ob eine Methode deklariert wird {noexcept/const/volatile/etc.} und sich entsprechend zu verhalten. Hier
ist ein Beispiel dafür, was Ich mag würde erreichen:
struct User{
UsedObject& obj;
User(UsedObject& obj) : obj(obj) {}
FORWARD_METHOD(obj, get); //here is where the forwarding happens
};
struct UsedObject{
string m{"Hello\n"};
string& get(double d){
cout << "\tUsed :const not called...\n";
return m;
}
const string& get(double d) const{
cout << "\tUsed :const called...\n";
return m;
}
};
Hier ist, was ich bisher **:
// forward with noexcept attribute
// I'm not 100% sure about : std::declval<std::add_lvalue_reference<decltype(obj)>::type
template<typename... Args>
constexpr decltype(auto) get(Args && ... args)
noexcept(
noexcept(std::declval<std::add_lvalue_reference<decltype(obj)>::type>().get( std::forward<Args>(args)... ))
and
std::is_nothrow_move_constructible<decltype(std::declval<std::add_lvalue_reference<decltype(obj)>::type>().get( std::forward<Args>(args)... ))>::value
)
{
cout << "const called...\n";
return obj.get(std::forward<Args>(args)...);
}
// forward with noexcept and const attributes
// I'm not sure that this one behave properly.
template<typename... Args>
constexpr decltype(auto) get(Args && ... args)
const noexcept(
noexcept(std::declval< std::add_const<decltype(obj) &>::type >().get( std::forward<Args>(args)... ))
and
std::is_nothrow_move_constructible<decltype(std::declval< std::add_const<decltype(obj) &>::type >().get( std::forward<Args>(args)... ))>::value
)
{
cout << "const not called...\n";
using const_type = std::add_lvalue_reference<std::add_const<std::remove_reference<decltype(obj)>::type>::type>::type;
return const_cast<const_type>(obj).get(std::forward<Args>(args)...);
}
Bitte beachten Sie, dass diese Frage anders aus dem folgenden ein, weil ich weiß, dass wir C++ - Eigenschaften verwenden können, um eine Objektschnittstelle zu überprüfen: Composition: using traits to avoid forwarding functions?
** inspiriert durch einen Faden der Kommentare mit @David S Ton hier: When should I use C++ private inheritance?.
Vielen Dank für Ihre sehr gute Antwort! Ich habe viel über Meta-Programmierung gelernt. Können wir es so benutzen? 'FORWARDING_MEMBER_FUNCTIONS (std :: zerfallen :: type, innere, Funktion)' Und mit Mitgliedszeiger: 'FORWARDING_MEMBER_FUNCTIONS (std :: zerfallen :: type, * ptr , Funktion); ' ? –
BTW, Was hindert C++ daran, die gleiche Syntax 'use inner.function;' für die Komposition bereitzustellen? –
@Julien__ Sie könnten das Makro ändern, um den Typ des Parameters zu akzeptieren. Der Nachteil ist, dass Sie Ihre Variablendeklaration vor dem Aufruf von FORWARDING_MEMBER_FUNCTIONS ausführen müssen. Wenn Sie den Typ explizit angeben, ist diese Einschränkung nicht vorhanden. Was besser ist, liegt an dir. Sie würden dies jedoch wahrscheinlich nicht mit Zeigern aufgrund von Referenzqualifikationsmerkmalen verwenden. Nichts hindert C++ daran, die Using-Syntax zur Weiterleitung an Funktionen von Mitgliedern zu verwenden, außer dass Sie das Komitee davon überzeugen müssen, es zu akzeptieren. –