Search code examples
c++templatesconstexprtemplate-meta-programmingcompile-time-type-checking

Detecting Instantiation/Calls with or without the constexpr Keyword in C++20 Constructors/Functions


I am currently trying to find a clean way to create a templated bytearray structure that can be initialized differently based on whether its constructor was instantiated with or without the constexpr keyword, And I also want to apply it to other methods and function if possible, I wonder if there is a way to achieve this?

Here is an example of what I want to achieve:

#include <iostream>
#include <cstring>

template<size_t N>
struct bytearray {
    char data[N];
    constexpr bytearray(char val) : data() {
        if constexpr (... is compile time instantiated ...) {
            for (size_t i = 0; i < N; ++i) {
                data[i] = val;
            }    
        } else {
            std::memset(data, val, N);     
        }
    }
};

int main() {
    constexpr bytearray<10> A(7);
    bytearray<10> B(7);
}

So instantiating the A class at compile time will use the for loop, then memcpy if it was not.


Solution

  • You are looking for if consteval:

        constexpr bytearray(char val) : data() {
            if consteval {
                for (size_t i = 0; i < N; ++i) {
                    data[i] = val;
                }    
            } else {
                std::memset(data, val, N);     
            }
        }
    

    This is a C++23 feature. In C++20, you can use std::is_constant_evaluated:

        constexpr bytearray(char val) : data() {
            if (std::is_constant_evaluated()) {
                for (char& byte : data) {
                    byte = val;
                }
            } else {
                std::memset(data, val, N);     
            }
        }
    

    Though note in this specific case, the check isn't necessary. for (size_t i = 0; i < N; ++i) data[i] = val; will be compiled to the same thing as a memset on any compiler worth its salt.