Chciałbym użyć kompozycji i napisać dobre metody przekazywania dla każdego możliwego przeciążenia (noexcept, const, volatile) przy użyciu C++.Przekazywanie metod ze składem zamiast dziedziczenia (przy użyciu cech C++)
Chodzi o wykorzystanie cech w celu określenia, czy dana metoda została zadeklarowana {noexcept/const/volatile/etc.} oraz odpowiednie zachowanie.
Oto przykład tego, co chciałbym osiągnąć:
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;
}
};
Oto co mam tak daleko **:
// 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)...);
}
Należy pamiętać, że ta kwestia jest inna od następujących jeden, ponieważ wiem, że możemy używać cech C++ do sprawdzenia interfejsu obiektu: Composition: using traits to avoid forwarding functions?
** inspirowany wątkiem komentarzy z @David S dźwięk tutaj: When should I use C++ private inheritance?.
Dziękuję za bardzo dobrą odpowiedź! Wiele się nauczyłem o metaprogramowaniu. Czy możemy używać go w ten sposób? 'FORWARDING_MEMBER_FUNCTIONS (std :: decay :: type, inner, function)' I ze wskaźnikiem dla członków: 'FORWARDING_MEMBER_FUNCTIONS (std :: decay :: type, * ptr , funkcja); ' ? –
BTW, Co uniemożliwia C++ dostarczanie tej samej składni "use inner.function;" dla kompozycji? –
@Julien__ Można zmienić makro, aby zaakceptować typ parametru. Wadą jest to, że musisz mieć deklarację zmiennych przed wywołaniem FORWARDING_MEMBER_FUNCTIONS, a jeśli wyraźnie określisz typ, to ograniczenie nie występuje. Co jest lepsze, zależy od Ciebie. Prawdopodobnie nie chciałbyś tego użyć ze wskaźnikami, ze względu na kwalifikatory referencji. Nic nie stoi na przeszkodzie, by C++ używało składni używania do przekazywania funkcji członkom, z wyjątkiem tego, że musiałbyś przekonać komisję, by to zaakceptowała. –