Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are function attributes inherited?

Tags:

If I have a virtual function that carries an attribute

[[nodiscard]] virtual bool some_function() = 0;

Does that attribute get implicitly applied to overrides of that function?

bool some_function() override;

Or do I need the attribute again?

[[nodiscard]] bool some_function() override;
like image 651
Cory Kramer Avatar asked Mar 30 '18 14:03

Cory Kramer


People also ask

Can attributes be inherited?

Subclasses can have two kinds of attributes: local and inherited. A local attribute is one that is defined on the subclass. An inherited attribute is one that is inherited from a parent product class. You customize an inherited attribute domain by editing its definition at the subclass level.

Are attributes inherited C++?

Basically: an attribute is not a member of the class or a constructor, so it can't be inherited.

What is a function attribute?

Function attributes are extensions implemented to enhance the portability of programs developed with GNU C. Specifiable attributes for functions provide explicit ways to help the compiler optimize function calls and to instruct it to check more aspects of the code.

Which function is not inherited?

Constructor cannot be inherited but a derived class can call the constructor of the base class. In C++, friend is not inherited. If a base class has a friend function, then the function does not become a friend of the derived class(es).


2 Answers

I sent an email to the C++ committee, specifically the Core working group, and provided the above example.

CoryKramer

It is currently unclear from the standard if attributes applied to virtual functions are inherited.

Response:

They are not. For them to be inherited, the Standard would have to explicitly say so, and it does not.

CoryKramer:

[After providing above code example] In the above example, I would expect both lines calling foo() to emit a compiler warning. I would hope that the attribute applies to all derived functions for consistency.

Response:

That's one perspective. Another is that, especially with covariant return types where the derived function returns a different type from that of the base function, it might very well be useful to make the base return type [[nodiscard]] but not the derived return type. There's currently no way to mark the derived function as not-[[nodiscard]].

More generally, it seems reasonable to get a different set of attributes when calling a derived function from those you get when calling the base function. If you know you have a derived class object, you have more specific information and behavior than if all you know is that it's a base class object, and attributes on member functions are part of that extra knowledge.

Reponses by Mike Miller of the C++ Core Working Group (3/30/2018).

like image 147
Cory Kramer Avatar answered Oct 10 '22 05:10

Cory Kramer


I can't see any evidence in the C++17 wording that attributes are inherited by overriding functions.

The most relevant section I can find is the rules for overriding:

[class.virtual]/2: If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list (11.3.5), cv-qualification, and ref-qualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides Base::vf. [..]

While this passage attacks the problem from a slightly different angle, I think it's enough to show that only virtualness is "inherited" (and that attributes don't come into play at all when deciding whether one function overrides another). That being said, I think this is slightly underspecified and could do with a clarifying note at the very least.

Of course, this quickly gets complicated. Given the below example:

struct B {
    [[nodiscard]] virtual bool foo() { return true; }
};

struct D : B {
    bool foo() override { return false; }
};

int main() {
    D().foo();
}

Clang will not issue a warning. However, access the function through a base pointer and it will.

struct B {
    [[nodiscard]] virtual bool foo() { return true; }
};

struct D : B {
    bool foo() override { return false; }
};

int main() {
    D d;
    ((B*)&d)->foo();
}

What that means for your question, I'm not sure.

Again, I'd like to see a bit more guidance from the standard on this topic.

like image 37
Lightness Races in Orbit Avatar answered Oct 10 '22 07:10

Lightness Races in Orbit