Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any way to pass arrays with unknown size to a lambda before C++20? [duplicate]

I have a macro that creates an instance of a class Info that accepts arrays with templated size as constructor arguments. The size information is used for checks.

I would like to do a check in this macro before returning the instance. The check could be something like a static_assert, but let's leave that open here. An elegant way to do the check is to make the macro call a lambda that performs the check(s) and then returns the instance.

But this fails because of a very annoying reason: if I pass char arrays to an auto argument of the lambda, they are deduced as char pointers and this prevents calling the Info constructor. So I would like to pass char arrays with templated size to the lambda. But this is only possible from C++20 on.

Is there any workaround? Can I make a lambda accept arrays of templated size with C++ 17?

Code:

#include <cstdlib>
#include <iostream>

class Info
{
  public:
    template <size_t function_length, size_t file_length>
    Info(const char (&function)[function_length], const char (&file)[file_length])
        : function(function)
        , file(file)
    {
        if ('\0' != function[function_length - 1])
        {
            this->function = "invalid";
        }

        if ('\0' != file[file_length - 1])
        {
            this->file = "invalid";
        }
    }

    const char* function;
    const char* file;
};

#define CREATE_INFO()                                                                                                  \
    (                                                                                                                  \
        []<std::size_t function_length, std::size_t file_length>(                                                      \
            const auto(&function)[function_length], const auto(&file)[file_length])                                    \
        {                                                                                                              \
            static constexpr char error_string[] = "invalid";                                                          \
                                                                                                                       \
            if ('m' != function[0])                                                                                    \
            {                                                                                                          \
                return Info(error_string, error_string);                                                               \
            }                                                                                                          \
            return Info(function, file);                                                                               \
        }(__FUNCTION__, __FILE__))

int main()
{
    Info info = CREATE_INFO();

    std::cout << "Function: " << info.function << ", file: " << info.file << std::endl;

    return 0;
}

Example in Compiler Explorer: https://godbolt.org/z/8q5zYKj4a

like image 632
Benjamin Bihler Avatar asked Oct 19 '25 04:10

Benjamin Bihler


1 Answers

Simply delete the template parts and take the variables by const&:

[](const auto&function, const auto&file) \
{ \
  static constexpr char error_string[] = "invalid"; \
  if ('m' != function[0]) { \
    return Info(error_string, error_string); \
  } \
  return Info(function, file); \
}(__FUNCTION__, __FILE__)

decay-to-pointer only happens if you convert to a value (bare auto include). The type of function in the above will be some reference-to-array (and same for file).

like image 116
Yakk - Adam Nevraumont Avatar answered Oct 21 '25 17:10

Yakk - Adam Nevraumont



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!