I want to apply the same template algorithm to std::vectors
which contain objects of some type T
and (different) std::vector
s which contain std::shared_ptr
s to objects of some type T
.
Can I distinguish these types in the template so that I could dereference the pointer when the object in the std::vector
is a std::shared_ptr
and don't do so if the type is not a std::shared_ptr
?
Here is the code:
#include <vector>
#include <memory>
struct S {
void member() const {}
};
void fn(const auto& arr) {
for (const auto& val : arr) {
// This won't compile with call fn(objects) below
const S& obj = *val;
// I want to have something like (I understand that I mix different things, I just want to show the idea)
const auto& obj = std::is_same<val, std::shared_ptr> ? (*val) : val;
// Or even better
const S& obj = std::is_same<val, std::shared_ptr> ? (*val) : val;
obj.member();
}
}
int main()
{
std::vector<S> objects;
std::vector<std::shared_ptr<S>> pointers;
// I want make 'fn' transparent for use containers of types T and std::shared_ptr<T>
fn(objects);
fn(pointers);
}
It seems that I can pass "de-wrapper" functor as a second argument to the call and make access over there, but I don't want to overcomplicate the client code.
You could add a type trait to check if a type is a std::shared_ptr<something>
:
#include <type_traits>
template<class T>
struct is_shared_ptr : std::false_type {};
template<class T>
struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {};
template<class T>
inline constexpr bool is_shared_ptr_v = is_shared_ptr<T>::value;
Example usage:
void fn(const auto& arr) {
for (const auto& val : arr) {
const S& obj = [&]() -> const S& {
if constexpr (is_shared_ptr_v<std::remove_cvref_t<decltype(val)>>) {
return *val;
} else {
return val;
}
}();
obj.member();
}
}