#c #variadic-templates
#c #переменные-шаблоны
Вопрос:
Есть ли способ сгенерировать статическую функцию (указатель), которая: 1. Имеет определенную подпись. 2. Возвращает конкретное значение. 3. Игнорирует все аргументы.
Что-то вроде:
template<typename ReturnType, ReturnType defaultValue, typename... Args>
ReturnType FallbackFunction(Args... ) {
return defaultValue;
}
int threeParamFunction(int one, int two, int three)
{
return one two three;
}
float twoParamFunction(float one, float two)
{
return one two;
}
int main()
{
// This somehow works
using ThreeParamFunction = decltype(amp;threeParamFunction);
ThreeParamFunction fncPointerZero = FallbackFunction<int, 0>;
cout << "Returning zero: " << fncPointerZero(5, 10, 15) << std::endl;
ThreeParamFunction fncPointerOne = FallbackFunction<int, 1>;
cout << "Returning one: " << fncPointerOne(5, 10, 15) << std::endl;
// Does not compile:
//using TwoParamFunction = decltype(amp;twoParamFunction);
//TwoParamFunction fncPointerSeven = FallbackFunction<float, 7.0f>;
//cout << "Returning seven: " << fncPointerSeven(5, 10) << std::endl;
return 0;
}
Мотивация заключается в создании резервной функции, которая возвращает известное значение, если приложение не может загрузить соответствующую функцию.
Комментарии:
1. «игнорирует»? … или
std::forward
s?2. Где определена функция twoParamFunction?
3. Почему бы просто не установить указатель на функцию
nullptr
и не проверить, что функция не равна нулю, прежде чем вызывать ее? Кроме того, в вашем примере, что не такint threeParamFunctionBackup(int, int, int) {return some_default_value;}
?4. @Peter В большинстве случаев вы правы. Но если у вас есть такие функции, как isSomethingEnabled, isSomethingPresent, загружаемые динамически и используемые во всем коде, вам не нужно проверять указатель перед каждым вызовом.
5. В этом случае
isSomethingEnabled
не следует динамически загружать. Это должна быть единственная функция, которая проверяет, была ли загружена динамически загружаемая функция перед ее вызовом. Если ваш пользовательский код ожидает вызова динамически загружаемой функции везде, ему необходимо сначала проверить эту функцию.
Ответ №1:
Вы не можете использовать адрес / тип функции шаблона (но вы можете для конкретных экземпляров).
итак, ваш
auto f0 = amp;FallbackFunction<int, 0>; // decltype(f0) is `int (*)()` not `int (*)(Ts...)`
но действительно, в вашем случае
int (*fncPointer)(int, int, int) = amp;FallbackFunction<int, 0>;
// Only FallbackFunction<int, 0, int, int, int> is valid
// it is mostly static_cast<int (*)(int, int, int)>(amp;FallbackFunction<int, 0>)
// Which force deduction to FallbackFunction<int, 0, int, int, int>.
Так что либо укажите все аргументы:
auto f2 = amp;FallbackFunction<int, 0, int, int>; // decltype(f2) is `int (*)(int, int)`
Или вы можете создать функтор с operator()
помощью (с помощью лямбда):
auto foo = [](auto...){ return 0; };
foo(); foo(1); foo(1, 2, 3);
auto bar = [](auto...){ return 4.2f; };
bar(); bar(1); bar(1, 2, 3);
Кроме того, float
недопустимый параметр, не относящийся к типу:
template <float f> struct S{}; // invalid.
Комментарии:
1. Более интересный вопрос, по-видимому, заключается в том, почему первая версия вообще работает? И чем она отличается от второго типа функции. Живой пример .
2. @super: пропустите этот момент.
float
недопустимый параметр, не относящийся к типу.3. Отлично, я могу взять этот функтор и присвоить его указателю, он вычтет правильный тип. Мне просто нужен отдельный функтор для каждого возвращаемого типа.