2

I have an hierarchy with an operator() overloading like the following

class Base{
public:
    virtual std::vector<float> operator()(const std::vector<float>& us) const {
        // some implementation like
        // return us;
    }

    virtual float operator()(float u) const = 0;
};

and a derived class

class Derived : public Base{
public:
    float operator()(float u) const override {
        return u;
    }
};

The invocation code looks like the code below (assume, the GetAVectorOfFloats second is indeed std::vector of floats).

Derived d;
auto [_, us] = GetAVectorOfFloats();
auto values = d(us);

However, the compiler (gcc version 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04)) spits

error: no match for call to ‘(Derived) (std::vector&)’

I observe, that const std::vector<float>& is not an option (but why?).

In case the code is more explicit

auto values = d.operator()(us);

the error becomes

error: cannot convert ‘std::vector< float>’ to ‘float’

Seems, like I'm missing something very basic? Can not I call the Base's operator() or is there some special syntax I should use?

5
  • There exists a Base::operator() that expects a vector, why it is not used? Commented Dec 18, 2024 at 13:26
  • d.Base::operator()(us); should work. See demo. Commented Dec 18, 2024 at 13:33
  • ((Base&)d)(us) also works Commented Dec 18, 2024 at 13:35
  • 2
    I haven't gone through the details of the question; this is just a debugging tip. Operator overloading doesn't introduce any magic. An overloaded operator is just a function with a weird name that can be called with a weird syntax. When I'm confused by an overloaded operator I replace it with a normally-named function, which helps me to see what's going on. Once I've sorted it out I go back to the overloaded operator. Commented Dec 18, 2024 at 13:36
  • 1
    This probably has to do with the fact that, quote, "C++ chooses the best overload based on the static type's of the function arguments" stackoverflow.com/questions/70671667/… and your object is of type Derived. If it was a pointer to Base, it would work. But why it doesn't look for overloads in the base class if there are none valid in the derived class, I don't know, but related: stackoverflow.com/questions/67873916/… Commented Dec 18, 2024 at 13:37

2 Answers 2

3

This is classic name hiding, nothing at all special about operator overloading:

When lookup for the name operator() is done in Derived (because that's the type of d) it finds float operator()(float u) const;.

Then name lookup terminates because the name has been found. There will not be any further lookup into the base class.

Solution is to make the other overload visible to name lookup in the scope of the derived class:

class Derived : public Base{
public:
    using Base::operator();
    float operator()(float u) const override {
        return u;
    }
};
Sign up to request clarification or add additional context in comments.

Comments

1

You encountered this problem because of name hiding.

You may see that if you overload neither of the operators (assuming they are not pure virtual), then both operators will work fine in the derived class.

Because you overloaded only one of the operators, the other effectively becomes hidden, as it is not directly a part of Derived.

To overcome this problem, you can either overload both operators, or explicitly bring the Base class' operators to scope:

class Derived : public Base {
public:
    using Base::operator();

    float operator()(float u) const override {
        return u;
    }
};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.