У меня есть макрос, который создает экземпляр класса Info, который принимает массивы шаблонного размера в качестве аргументов конструктора. Информация о размере используется для проверок.
Я хотел бы проверить этот макрос перед возвратом экземпляра. Чек может быть чем-то вроде static_assert, но давайте оставим его открытым здесь. Элегантный способ выполнить проверку — заставить макрос вызывать лямбду, которая выполняет проверку(и), а затем возвращает экземпляр.
Но это не удается по очень досадной причине: если я передаю массивы символов в аргумент auto лямбды, они выводятся как указатели char, и это предотвращает вызов конструктора Info. Поэтому я хотел бы передать массивы символов с шаблонным размером в лямбду. Но это возможно только начиная с C++20.
Есть ли обходной путь? Могу ли я заставить лямбду принимать массивы шаблонного размера с помощью C++ 17?
Код:
#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;
}
Пример в Compiler Explorer: https://godbolt.org/z/8q5zYKj4a
@Элджей, возможно, это тоже возможно. Но передача ссылок auto более элегантна. :-)
Зависит от. Когда магия auto не приводит к благословению, она, как правило, превращается в проклятие. Если это не элегантное решение, то это, наверное, полный ум<ругательство удалено>.
Почему бы просто не создать обычный шаблон функции и не заставить макрос вызывать эту функцию с помощью макроса исходного местоположения? Пример #define CREATE_INFO normal_create_info_function(__FUNCTION__, __FILE__).
@FrançoisAndrieux Это тоже должно сработать, вы правы. Тем не менее, лямбда мне нравится больше, поскольку это всего лишь вспомогательная структура для выполнения каких-то проверок.





Просто удалите части шаблона и возьмите переменные по 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__)
распад до указателя происходит только в том случае, если вы конвертируете в значение (голый auto включаете). Тип function в приведенном выше примере будет ссылкой на массив (то же самое и для file).
Вместо этого передать начальные и конечные итераторы?