Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constexpr member function

Suppose I have a struct template S that is parametrized by an engine:

template<class Engine> struct S;

I have two engines: a "static" one with a constexpr member function size(), and a "dynamic" one with a non-constexpr member function size():

struct Static_engine {
    static constexpr std::size_t size() {
        return 11;
    }
};

struct Dynamic_engine {
    std::size_t size() const {
        return size_;
    }
    std::size_t size_ = 22;
};

I want to define size() member function in S that can be used as a constexpr if the engine's size() is constexpr. I write:

template<class Engine>
struct S {
    constexpr std::size_t size() const {
        return engine_.size();
    }
    Engine engine_;
};

Then the following code compiles with GCC, Clang, MSVC and ICC:

S<Static_engine> sta;         // not constexpr
S<Dynamic_engine> dyn;

constexpr auto size_sta = sta.size();
const auto size_dyn = dyn.size();

Taking into account intricacies of constexpr and various "ill-formed, no diagnostic is required", I still have the question: is this code well-formed?

Full code on Godbolt.org

(I tagged this question with both c++17 and c++20 in case this code has different validity in these two standards.)

like image 562
Evg Avatar asked Nov 14 '19 21:11

Evg


2 Answers

The code is fine as written.

[dcl.constexpr]

6 If the instantiated template specialization of a constexpr function template or member function of a class template would fail to satisfy the requirements for a constexpr function or constexpr constructor, that specialization is still a constexpr function or constexpr constructor, even though a call to such a function cannot appear in a constant expression. If no specialization of the template would satisfy the requirements for a constexpr function or constexpr constructor when considered as a non-template function or constructor, the template is ill-formed, no diagnostic required.

The member may not appear in a constant expression for the specialization that uses Dynamic_engine, but as the paragraph above details, that does not make S::size ill-formed. We are also far from ill-formed NDR territory, since valid instantations are possible. Static_engine being a prime example.

The quote is from n4659, the last C++17 standard draft, and similar wording appears in the latest C++20 draft.


As for the evaluation of sta.size() as a constant expression, going over the list at [expr.const] I cannot find anything that is disallowed in the evaluation itself. It is therefore a valid constant expression (because the list tells us what isn't valid). And in general for a constexpr function to be valid, there just needs to exist some set of arguments for which the evaluation produces a valid constant expression. As the following example form the standard illustrates:

constexpr int f(bool b)
  { return b ? throw 0 : 0; }           // OK
constexpr int f() { return f(true); }   // ill-formed, no diagnostic required

struct B {
  constexpr B(int x) : i(0) { }         // x is unused
  int i;
};

int global;

struct D : B {
  constexpr D() : B(global) { }         // ill-formed, no diagnostic required
                                        // lvalue-to-rvalue conversion on non-constant global
};
like image 171
StoryTeller - Unslander Monica Avatar answered Sep 22 '22 19:09

StoryTeller - Unslander Monica


Yes.

Functions may be marked as constexpr without being forced to be evaluated at compile-time. So long as you satisfy the other requirements for marking a function as constexpr, things are okay (returns a literal type, parameters are literals, no inline asm, etc.). The only time you may run into issues is if it's not actually possible to create arguments that satisfy the function being called as a core constant expression. (e.g., if your function had undefined behavior for all values, then your function would be ill-formed NDR)

In C++20, we received the consteval specifier that forces all calls to the function to be able to produce a compile-time constant (constexpr).

like image 37
AndyG Avatar answered Sep 21 '22 19:09

AndyG