#c #c-preprocessor
#c #c-препроцессор
Вопрос:
У меня есть несколько функций в пространстве имен. Параметры разные, для каждого вызова они сохраняют объект, содержащий строковый элемент, в вектор. В пространстве имен нет перегруженных функций.
Я хотел бы создать макрос, который выдает лямбда-выражение для сопоставления объектов, созданных с помощью вызова определенной функции. В дополнение к этому макрос также должен приводить к ошибке времени компиляции, если функция с именем, указанным в качестве параметра, не существует в пространстве имен. Влияние на результаты в случае успешной компиляции? (Если это вообще возможно, результаты компиляции с этой проверкой и без нее будут одинаковыми, не полагаясь на код, который может быть или не быть оптимизирован в зависимости от уровня оптимизации.) Возможно ли это? Если это возможно: как я могу это реализовать?
Пример того, чего я пытаюсь достичь; макрос, о котором я спрашиваю, это CALL_INFO_PREDICATE
; static_assert_function_exists
часть является заполнителем для любого кода, который позволит достичь желаемого результата:
struct CallInfo
{
const std::string m_function;
CallInfo(const std::stringamp; function)
: m_function(function)
{
}
}
std::vector<CallInfo*> g_calledFunctions;
namespace mymath
{
// all functions with same return type, but differnent parameter lists
double sin(double radian)
{
g_calledFunctions.push_back(new CallInfo("sin"));
...
}
double atan2(double y, double x)
{
g_calledFunctions.push_back(new CallInfo("atan2"));
...
}
}
#define CALL_INFO_PREDICATE(functionName) [] (CallInfo* info) -> bool
{
static_assert_function_exists(mymath::functionName);/* << how to make this work? */
return info->m_function == #functionName;
}
int main ()
{
mymath::sin(1);
mymath::atan2(3, 7);
auto pos = std::find_if(g_calledFunctions.begin(), g_calledFunctions.end(), CALL_INFO_PREDICATE(sin)); // compiles; function sin exists in mymath
auto pos2 = std::find_if(g_calledFunctions.begin(), g_calledFunctions.end(), CALL_INFO_PREDICATE(cos)); // produces compile time error, since there is no function named cos in mymath
...
}
Ответ №1:
Почему бы не сохранить указатели на функции в CallInfo
и устранить необходимость в макросах?
struct CallInfo
{
const std::string m_function;
void* m_function_ptr;
CallInfo(const std::stringamp; function, void* function_ptr)
: m_function(function),
m_function_ptr(function_ptr)
{
}
}
std::vector<CallInfo*> g_calledFunctions;
namespace mymath
{
// all functions with same return type, but differnent parameter lists
double sin(double radian)
{
g_calledFunctions.push_back(new CallInfo("sin", sin));
...
}
double atan2(double y, double x)
{
g_calledFunctions.push_back(new CallInfo("atan2", atan2));
...
}
}
int main ()
{
mymath::sin(1);
mymath::atan2(3, 7);
auto pos = std::find_if(g_calledFunctions.begin(), g_calledFunctions.end(), [](CallInfo* info) { return info->m_function_ptr == amp;mymath::sin; });
auto pos2 = std::find_if(g_calledFunctions.begin(), g_calledFunctions.end(), [](CallInfo* info) { return info->m_function_ptr == amp;mymath::cos; });
// ...
}
Теперь компилятор может автоматически проверить, существует ли функция.
Ответ №2:
Вы можете просто использовать его, предполагая отсутствие перегрузок:
#define CALL_INFO_PREDICATE(functionName) [] (CallInfo* info) -> bool
{
static_cast<void>(amp;mymath::functionName);
return info->m_function == #functionName;
}
приведение к void
, чтобы избежать предупреждения о неиспользуемом выражении.
Комментарии:
1. Вы случайно не знаете, гарантированно ли C оптимизирует это или это просто очень вероятно в соответствии со стандартом? (Кстати: извините, что я не буду предоставлять обратную связь в течение некоторого времени. Не могу проверить это сразу, но это выглядит многообещающе.)
2. Получение адреса не выполняется.
3. @fabian amp;math::functionName по сути является постоянным значением. Это не может быть преобразовано в код, даже если компилятор попытается.