Функции с переменным числом параметров

Рейтинг: 7Ответов: 3Опубликовано: 29.04.2015

Как передать переменное количество параметров х и у одной функции. Из этой задачи:

Написать функцию (или макроопределение), которая определяет принадлежит ли точка с координатами (х , у) окружности с заданным радиусом R. Написать функцию belong с переменным числом параметров, которая определяет сколько точек с координатами (х , у) принадлежат заданной окружности. Написать вызывающую функцию main, которая обращается к функции belong не менее трех раз с количеством параметров 3, 9, 11.

Cамо решение задачи не нужно.

Ответы

▲ 4

Проблема в том, как группировать x и y.

Мы можем засунуть их в структуру, например struct Point { float x, y; }; тогда задача сводится к "как написать функцию принимающую переменное количество параметров". Это просто, для этого есть шаблоны:

#include <initializer_list>
#include <utility>

struct Point { float x, y; };

template<typename... T>
int f(const T&... args) {
    auto n = 0;
    auto R = 10;
    for (auto&& p : std::initializer_list<Point>{args...})
        if (p.x*p.x + p.y*p.y - R*R < 0.0001)
            ++n;
    return n;
}

int main() {
    f(Point{11, 12}, Point{22, 23});
}

Если же мы хотим передавать координаты последовательно, т.е. f(x1, y1, x2, y2), то мы опять можем использовать шаблоны, но уже с рекурсией:

int f() {
    return 0;
}
template<typename... T>
int f(float x, float y, const T&... tail) {
    return int(x*x + y*y - R*R < 0.0001) + f(tail...);
}
▲ 4

Если это задание из ВУЗа, то вполне вероятно, что ожидается что-нибудь подобное:

#include <iostream>
#include <cstdarg>  

int max(size_t number, ...)
{
    va_list argList;
    va_start(argList, number);
    int max = va_arg(argList, int);
    for(size_t i = 1; i < number; ++i)
    {
        int val = va_arg(argList, int);
        max = std::max(val, max);
    }
    va_end(argList);
    return max;
}

int main()
{
    int maxVal = max(6, 12, 43215, 61, 516, 412222, 65125);
    std::cout << "Max value is: " << maxVal << std::endl;
    return 0;
}

В примере используется функция с переменным количеством параметров, где количество параметров задаётся первым. Решение предложенное @Abyx гораздо лучше, но есть и такое, которое унаследовано от C.

▲ 1

Variadic templates здесь использовать не нужно. Шаблонная магия - это что-то вроде кунг-фу. Настоящие мастера не используют её без необходимости. Кроме того, в данной ситуации это было бы просто неправильно методологически. Количество параметров слишком велико, а тип у них один и тот же. Variadic templates существуют в языке определённо не для таких случаев. Для таких случаев существуют контейнеры и итераторы.

Приятным бонусом при использовании контейнера будет то, что функция для подсчёта элементов, удовлетворяющих некоторому условию, уже есть в стандартной библиотеке. Всё, что нужно сделать, это написать для неё обёртку, содержащую конкретное условие.

#include <vector>
#include <algorithm>
using namespace std;

struct Point {
    float x, y;
    Point(float x_, float y_) : x(x_), y(y_) { }
};

template <typename It>
size_t belong(It first, It last, double r) {
    return count_if(first, last,
        [r](const typename It::reference itm) {
            return pow(itm.x, 2)+pow(itm.y, 2)-pow(r, 2) < 0.0001;
        });
}

int main()
{
    vector<Point> points;
    points.emplace_back(1.0, 1.0);
    points.emplace_back(2.0, 2.0);
    points.emplace_back(3.0, 3.0);

    size_t count = belong(begin(points), end(points), 10);

    // далее аналогично для 9 и 11 точек

    return 0;
}