Следующий код будет скомпилирован с error: call of overloaded 'f(int)' is ambiguous
Могу ли я решить эту проблему без использования va_list
когда я звоню f
с одним параметром?
Это для функции printf. Мне просто интересно, смогу ли я повысить эффективность работы с простым делом отдельно, не вводя новое имя.
Есть ли обходной путь?
#include <cstdarg>
void f(int n, ...) {
va_list args;
va_start(args, n);
//Do something
va_end(args);
}
void f(int n) {
//Do something without va_list
}
int main() {
f(42);
return 0;
}
Вы не можете иметь эту перегрузку (явно), так как она всегда будет неоднозначной. Следующие параграфы в стандарте имеют отношение, я думаю:
1 Из набора функций-кандидатов, построенных для данного контекста
([over.match.funcs]), выбирается набор жизнеспособных функций, из которых
лучшая функция будет выбрана путем сравнения преобразования аргументов
последовательности для лучшего соответствия ([Over.match.best]). Выбор
Жизнеспособные функции учитывают отношения между аргументами и
параметры функции, кроме ранжирования конверсионных последовательностей.2 Во-первых, чтобы быть жизнеспособной функцией, функция-кандидат должна иметь
Достаточно параметров для согласования по количеству с аргументами в списке.
Если в списке m аргументов, все функции-кандидаты, имеющие ровно m параметров, являются жизнеспособными.
Функция-кандидат, имеющая менее m параметров, является жизнеспособной, только если она имеет многоточие в своем списке параметров ([dcl.fct]). Для
цели разрешения перегрузки, любой аргумент, для которого нет
соответствующий параметр считается «совпадающим с многоточием»
([over.ics.ellipsis]).Функция-кандидат, имеющая более m параметров, является жизнеспособной, только если (m + 1) -й параметр имеет аргумент по умолчанию.130 Для целей
разрешение перегрузки, список параметров усекается справа, поэтому
что есть ровно m параметров.
Таким образом, обе перегрузки являются жизнеспособными функциями для вызова. Теперь компилятор должен определить, какой вариант лучше подходит, основываясь на последовательности преобразования для предоставленного вами аргумента. И оба они одинаково хороши в этом отношении, в любом случае не требуется преобразования для 42.
Давайте воспользуемся другими правилами перегрузки. Функция шаблона, сгенерированная и найденная в разрешении перегрузки, считается меньшим соответствием, чем функция без шаблона. Итак, давайте сделаем версию многоточия шаблоном:
#include <iostream>
#include <type_traits>
#include <cstdarg>
void vf(int n, std::va_arg args) {
//Do something with args
}
template<typename T>
auto f(T n, ...)
-> std::enable_if_t<std::is_same<T, int>::value> {
std::va_list args;
va_start(args, n);
vf(n, args);
va_end(args);
}
void f(int n) {
//Do something without va_list
}
int main() {
f(42);
f(42, 53);
return 0;
}
Но мы применим SFINAE к возвращаемому типу, поэтому его можно создать только тогда, когда T является целым числом (таким образом, давая вам исходную функцию). Теперь версия с многоточием выбирается только тогда, когда версия с одним параметром больше не является жизнеспособной, то есть когда имеется более одного параметра.
Других решений пока нет …