Question Details

No question body available.

Tags

c++ constraints overriding require virtual

Answers (4)

December 15, 2025 Score: 11 Rep: 228,654 Quality: Expert Completeness: 80%

Why?

Because the standard says so :)

I would say that the rationale is to avoid having to decide whether different requires hide or override base function.

Imagine valid code:

template 
concept isEven = ((I % 2) == 0);

template struct Base {

void f() requires (isEven) { std::cout
December 15, 2025 Score: 3 Rep: 47,814 Quality: Medium Completeness: 80%

I don't understand the motivation behind this.

It is mentioned in issue 2488 that this may not be implementable in some ABIs:

This would indicate that a virtual function (which cannot have a trailing requires-clause, per 11.7.3 [class.virtual] paragraph 6) can be overloaded with a non-virtual member function with the same parameter type list but with a trailing requires-clause. However, this is not implementable on some ABIs, since the mangling of the two functions would be the same. For example:

#include 
 template
 struct Foo {
    virtual void fun() const {}
    void fun() const requires std::isobjectv {}
 };
 int main() {
   Foo{}.fun();
 }

Should such overloading be ill-formed or conditionally-supported, or should the current rules be kept?

December 15, 2025 Score: 3 Rep: 29,865 Quality: Medium Completeness: 80%

Just because a function does not participate in overload resolution (which is what requires false does) does not mean that function doesn't exist. For example, notice the difference between

struct base { void foo(); };
template struct derived : base {
  void foo() requires std::issamev;
};
int main() { derived().foo(); } // error

and

struct base { void foo(); };
template struct derived : base { };
template struct derived : base { void foo(); };
int main() { derived().foo(); } // fine

In the first, derived does in fact have a member function named foo. You just can never call it or even form a pointer to it, since both those operations perform overload resolution. But you can detect it in that name lookup for a call to foo on a derived will hit the declaration in derived and stop base::foo from ever being considered. This is different from what happens if you arrange so that derived truly does not contain a member named foo at all.

I think the behavior you're seeing with virtual makes more sense with the above remark in mind. Even if you were to delete the bit of the standard that prohibits virtual functions from having requires-clauses, you still wouldn't change the fact that a failing constraint does not cause the entire declaration to act like it doesn't exist. In particular, the way virtual functions work (that is, the way that the function being overridden by a certain declaration is determined, and/or the way that the final overrider of a virtual function is determined) does not involve overload resolution, but rather correspondence of signatures. Thus, like name resolution, virtual function overriding is one of those non-overload-resolving mechanisms that can detect present but non-participating overloads.

If we were to imagine a C++ standard with [class.virtual]/6 deleted, your code would still not function as intended. Your Derived would contain a declaration of f that would happen not to be callable but that would at the same time be the final overrider of f in Derived. Even without poring through the standard to determine what would happen (and why would we be guaranteed an answer to such a hypothetical anyway?), I think we can say that this won't work. (Though, actually, I think that [basic.def.odr]/8 is general enough that the standard can be considered to cover this hypothetical).

Given the potentially confusing semantics of virtual functions with requires-clauses, it makes sense to just ban them outright.

December 16, 2025 Score: 0 Rep: 13,181 Quality: Medium Completeness: 60%

Regarding your verbose example, where you condition the entire Derived class by requiring T to be int and then overriding f: this is clear and unambiguous. Only Derived is a valid type and you can choose to use that or any other Base including Base, in which case you don't get Derived's overload.

For this particular case, it would likely be simpler to declare non-template Derived which inherits from Base, however.

Your original example is a very different animal. Here, you're allowing any Derived and then trying to condition f specifically where T is int. But what does a requires clause on an override even mean? Does it only override when the condition is true, and fall back to base implementation otherwise? Does it become illegal to call it (well, that can't be the case, because it could always be called via base pointer)? Is it legal to define multiple overrides with mutually-exclusive requirements? What about non-exclusive requirements?

The standard is silent on all these questions, because it explicitly forbids doing it in the first place. What is currently forbidden may later be permitted, once people have figured out the answers to these and other questions.