if constexpr (requires { []<int>(){}.template operator()<(T(args...), void(), 0)>(); }) 

This appears to work and is much better than what I came up with, thank you.

It has the same limitation that args must be passable as NTTP (motivating a macro for constexpr values which cannot be used as NTTPs), but this is an improvement and I appreciate it.

> Can you give more details and an actual, small example of what the comments would actually be? I'm having trouble visualising what code would exist that depends on an unknown type's ability to be constructed constexprly.
> In other words, can you give more details on what this functionality would enable?

Sure. 

The actual context where I needed it was for a slab heap which uses CRTP for objects with a common base.

The class looks a little like:

template<typename Derived, typename Base> requires std::derived_from<Base, BaseObject>
class SlabAllocatable : public Base {
    private:
        static constinit inline SlabHeap<Derived> s_slab_heap;
    public:
        // ...
        static Derived *Create();
};

A class which uses this would look something like:

class MyObject : public SlabAllocatable<MyObject, BaseObject> { /* ... */ };

The objects which can use this template all share a common base class, and this base class has a virtual method to retrieve an integer class token. 

i.e. BaseObject has virtual ClassTokenType GetClassToken() = 0;

The base class has a member field to cache the class token. Doing this enables class token retrieval from BaseObject* without having to make any virtual calls, by returning m_ClassTokenCache.

I would like to set the class token cache in the base class constructor, but this is not possible because a base class cannot call derived class virtual functions until the derived class constructor has finished.

My desired usage for is_constexpr_constructible looks something like:

template<typename Derived, typename Base>
Derived *SlabAllocatable::Create() {
        Derived *obj = Allocate(); // obj has been fully constructed here, and has m_ClassTokenCache = 0;
        if constexpr (is_constexpr_constructible_v<Derived>) {
            constexpr ClassTokenType ClassToken = d{}.GetClassToken(); // Valid if d is constexpr constructible and has constexpr virtual implementation of GetClassToken().
            obj->InitializeClassTokenCache(ClassToken); // This sets the class token cache without having to perform a virtual call at runtime.
        } else {
            obj->InitializeClassTokenCache(obj->GetClassToken()); // This performs a virtual call in the process of getting the class token.
        }
        return obj;
}

In particular, knowing whether or not an object is constexpr-constructible would enable me to attempt to construct one and retrieve its class token via the GetClassToken() method, preventing the need for the virtual call.

Without the if constexpr construction, trying to get the class token would result in a compiler-error in the case where it's not possible.

I have thought about e.g. if constexpr (requires { Derived::GetClassTokenStatic(); }), but this causes there to be more than one source of truth for an object's token, which seems undesirable.

I did see while searching some other, related use cases for checking constexpr-evaluability: https://stackoverflow.com/questions/55288555/c-check-if-statement-can-be-evaluated-constexpr

I have wanted this kind of introspection in a number of other contexts, as well. Hopefully the above is clarifying.

Best,
Michael Scire


On Sat, Oct 23, 2021 at 8:21 AM Thiago Macieira via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
On Saturday, 23 October 2021 00:27:30 PDT Michael Scire via Std-Proposals
wrote:
> In particular, a common use case might be like:
>
> ```
>     if constexpr (std::is_constexpr_constructible<T>::value) {
>         constexpr T t{/* potentially arguments here */};
>         // Use t as a non-type-template parameter, or use it in other
> compile-time only ways like for static asserts.
>     } else {
>         T t{/* potentially arguments here */};
>         // Use t as a runtime value.
>     }
> ```

Can you give more details and an actual, small example of what the comments
would actually be? I'm having trouble visualising what code would exist that
depends on an unknown type's ability to be constructed constexprly.

In other words, can you give more details on what this functionality would
enable?

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel DPG Cloud Engineering



--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals