Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Checking for constexpr in a concept

I just started doing concepts. The syntax for checking expressions is really useful and removes me a lot of boilerplate I had with sfinae. However I wondered how can I check if an expression can be used in a constexpr context. Sometimes those expression results in void. The way I can imagine would look like this, with the constexpr keyword uncommented:

template<typename T>
concept foo = requires(T t) {
    /* constexpr */ { t.bar(); } -> std::same_as<void>;
    /* constepxr */ { T::foo; };
}

However, I highly doubt this is the right syntax. Is there an easy way to check for the constexpr-ness of the expression in a concept?

I don't want to check if the evaluation of a constexpr function won't fail for all possible values of t, I want to know if I can put that expression at a place where the compiler expect something to be evaluable at compile time.

like image 833
Guillaume Racicot Avatar asked Aug 09 '20 12:08

Guillaume Racicot


People also ask

Is constexpr always evaluated at compile time?

constexpr functions will be evaluated at compile time when all its arguments are constant expressions and the result is used in a constant expression as well.

When can a function be constexpr?

A constexpr function is one whose return value is computable at compile time when consuming code requires it. Consuming code requires the return value at compile time to initialize a constexpr variable, or to provide a non-type template argument.

Does constexpr improve performance?

In Conclusion. constexpr is an effective tool for ensuring compile-time evaluation of function calls, objects and variables. Compile-time evaluation of expressions often leads to more efficient code and enables the compiler to store the result in the system's ROM.

How do I know if a function is constexpr?

The easiest way to check whether a function (e.g., foo ) is constexpr is to assign its return value to a constexpr as below: constexpr auto i = foo(); if the returned value is not constexpr compilation will fail.


Video Answer


1 Answers

I think the expected concept can be created using std::bool_constant, which has the property that the failure of substitution in its argument of not-constant expression is not a compilation error, but just makes the concept false.

The proposed solution is

#include <concepts>
#include <type_traits>

template<typename T>
concept HasConstexprVoidBar = 
requires(T t) {
    { t.bar() } -> std::same_as<void>;
    { std::bool_constant<(T{}.bar(), true)>() } -> std::same_as<std::true_type>;
};

struct A {
    constexpr void bar() {}
};

struct B {
    void bar() {}
};

int main() {
    // concept check passes for constexpt A::bar()
    static_assert( HasConstexprVoidBar<A> );
    // concept check fails for B::bar()
    static_assert( !HasConstexprVoidBar<B> );
}

Here the concept HasConstexprVoidBar is verified successfully for struct A having constexpr void method bar and evaluates to false for struct B having not-constexpr method.

Demo: https://gcc.godbolt.org/z/nsx9z99G4

like image 66
Fedor Avatar answered Oct 13 '22 06:10

Fedor