JHBonarius
JHBonarius

Reputation: 11271

operator >> is not defined why?

I'm trying to help with this question, and I think I found a nice solution. But it's kind of complex due to all the wrapping I need. I would want to overload operator>> to allow for easy chaining notation. But it's not working as I expected.

I can do:

#include <functional>
#include <memory>

template<typename T>
class Object {
private:
    T* const ptr{ nullptr };
public:
    Object(T* ptr) noexcept : ptr(ptr) {}
    T* Get() const noexcept { return ptr; }
};

using MyObject = Object<int>;

template <typename T, typename MemFn>
auto fnc (T* ptr, MemFn memFn)
-> decltype(std::invoke(memFn, std::declval<T>())) {
    if (ptr) return std::invoke(memFn, *ptr);
    return nullptr;
}

int main() {
    std::unique_ptr<MyObject> myObjectPtr = std::make_unique<MyObject>(nullptr);
    [[maybe_unused]] int* optionalTarget = fnc(myObjectPtr.get(), &MyObject::Get);
}

However, I want to do

#include <functional>
#include <memory>

template<typename T>
class Object {
private:
    T* const ptr{ nullptr };
public:
    Object(T* ptr) noexcept : ptr(ptr) {}
    T* Get() const noexcept { return ptr; }
};

using MyObject = Object<int>;

template <typename T, typename MemFn>
auto operator>> (T* ptr, MemFn memFn)
-> decltype(std::invoke(memFn, std::declval<T>())) {
    if (ptr) return std::invoke(memFn, *ptr);
    return nullptr;
}

int main() {
    std::unique_ptr<MyObject> myObjectPtr = std::make_unique<MyObject>(nullptr);
    [[maybe_unused]] int* optionalTarget = myObjectPtr.get() >> &MyObject::Get;
}

What does work, but what I consider ugly is

#include <functional>
#include <memory>
#include <optional>

template<typename T>
class Object {
private:
    T* const ptr{ nullptr };
public:
    Object(T* ptr) noexcept : ptr(ptr) {}
    T* Get() const noexcept { return ptr; }
};

using MyObject = Object<int>;

template <typename T>
auto makeOptRef(T* ptr) -> std::optional< std::reference_wrapper<T>> {
    if (ptr) return std::ref(*ptr);
    return {};
}

template <typename T, typename MemFn>
auto operator>> (std::optional<std::reference_wrapper <T>> ptr, MemFn memFn)
-> std::optional<std::reference_wrapper<std::remove_pointer_t<decltype(std::invoke(memFn, std::declval<T>()))>>> {
    if (ptr) return makeOptRef(std::invoke(memFn, *ptr));
    return {};
}

int main() {
    std::unique_ptr<MyObject> myObjectPtr = std::make_unique<MyObject>(nullptr);
    std::optional<std::reference_wrapper<MyObject>> myObjOptRef = makeOptRef(myObjectPtr.get());

    std::optional<std::reference_wrapper<int>> optionalTarget = myObjOptRef >> &MyObject::Get;

    [[maybe_unused]] int output = (optionalTarget) ? optionalTarget->get() : -1;
}

Upvotes: 2

Views: 145

Answers (1)

Any pointer type is a built-in type, as are pointers to members. You are trying to overload an operator for two built-in types, that's simply a non-starter. At least one argument must be of a user-defined type, or a reference to it.

You can get it to work by passing a T& instead of a T*.

Upvotes: 8

Related Questions