Vorrei utilizzare la composizione e scrivere buoni metodi di inoltro per ogni possibile sovraccarico (noxcept, const, volatile) utilizzando le funzionalità C++.Inoltro del metodo con composizione invece dell'ereditarietà (utilizzando i tratti del linguaggio C++)
L'idea è di utilizzare i tratti per determinare se un metodo è dichiarato {noxcept/const/volatile/ecc.} E di comportarsi di conseguenza.
Ecco un esempio di quello che vorrei realizzare:
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;
}
};
Ecco quello che ho finora **:
// 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)...);
}
prega di notare che questa domanda è diversa da quella seguente uno, perché so che possiamo usare i tratti C++ per ispezionare un'interfaccia oggetto: Composition: using traits to avoid forwarding functions?
** ispirato da una discussione di commenti con @David S tono qui: When should I use C++ private inheritance?.
Grazie per la tua ottima risposta! Ho imparato molto sulla meta-programmazione. Possiamo usarlo in questo modo? 'FORWARDING_MEMBER_FUNCTIONS (std :: decay :: type, inner, function)' E con il puntatore membro: 'FORWARDING_MEMBER_FUNCTIONS (std :: decay :: type, * ptr , funzione) ? –
BTW, Cosa impedisce al C++ di fornire la stessa sintassi 'use inner.function;' per la composizione? –
@Julien__ È possibile modificare la macro per accettare il tipo di parametro. Lo svantaggio è che è necessario che la dichiarazione della variabile si verifichi prima di richiamare FORWARDING_MEMBER_FUNCTIONS, mentre se si specifica esplicitamente il tipo, tale restrizione non è presente. Quale è meglio dipende da te. Probabilmente non vorresti usarlo con i puntatori, tuttavia, a causa dei qualificatori di riferimento. Niente impedisce a C++ di utilizzare la sintassi usando per inoltrare le funzioni dei membri, tranne per il fatto che dovresti convincere il comitato ad accettarlo. –