pat
pat

Reputation: 823

C++ constexpr auto member function. Clang issue?

 #include <utility>

 struct A {
     constexpr auto one(int a) {
         return std::integral_constant<int, _data[a]>{};
     }
     constexpr int  two(int a) const {
         return _data[a];
     }

     int _data[10];
 };

 int main() {
     constexpr auto ex = A{{1,2,3,4,5,6,7,8,9,10}};

     std::integral_constant<int, ex.two(3)> b{};
 }

The code above will not compile in trunk Clang. The error is in the one() member function, and says:

cc.cpp:57:44: note: implicit use of 'this' pointer is only allowed 
  within the evaluation of a call to a 'constexpr' member function.

Obviously, the function is marked constexpr, and if you comment out the one() member, everything compiles fine, so we are clearly able to create the integral_constant from the ex, but not directly from the struct? It seems like, when I need the auto return type deduction, it fails and claims the function is not constexpr?

Is this expected? I feel like it should not be a problem, and I would be surprised if this was expected behavior.

Upvotes: 6

Views: 2689

Answers (2)

polkovnikov.ph
polkovnikov.ph

Reputation: 6632

  1. constexpr functions are made so that they can be called both at compile-time and run-time.
  2. Code with a constexpr function is well-formed if you can omit constexpr and get a proper plain function. In other words it must compile as a run-time function.
  3. If the body of constexpr function cannot be calculated at compile-time, it's still compiled, but you cannot use it in a compile-time context such as template arguments.
  4. If constexpr method is called on constexpr object, this is considered constexpr.

In case of one it is ill-formed, because when it's compiled to be run at run-time, _data[a] is considered to be a run-time expression, because a is not a constant expression, even though this and this->_data are.

In case of two it compiles fine, because it works fine at runtime, and at compile-time this is constexpr as much as a, so that this->_data[a] is constexpr and everything works fine.

Upvotes: 2

Barry
Barry

Reputation: 304142

If you consider this statement in [dcl.constexpr]/7:

A call to a constexpr function produces the same result as a call to an equivalent non-constexpr function in all respects except that a call to a constexpr function can appear in a constant expression.

Consider the non-constexpr equivalent function A::one(). _data[a] cannot be used in a constant expression (as a non-type template argument) because it would involve the evaluation of this, from [expr.const]:

A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine (1.9), would evaluate one of the following expressions:
(2.1) — this (5.1.1), except in a constexpr function or a constexpr constructor that is being evaluated as part of e;

Since the non-constexpr equivalent is ill-formed, it is reasonable that the constexpr function give the same result.

Ont the other hand, two() is a well-formed member function regardless of constexpr and your use of ex.two(3) is valid as a constant expression - that's why it compiles.

Upvotes: 7

Related Questions