C ++ шаблоны, эффективная функция для загрузки точек - PullRequest
3 голосов
/ 08 февраля 2011

Я бы хотел реализовать функцию загрузки 1D / 2D / 3D точек из файла ... Параметр шаблона Point может быть 1D 2D 3D точкой.

template <typename Point>
void List <Point> ::load ( const char *file)
{

            ...

            for ( unsigned int i = 0; i < file.size(); i++ )
            {

                   if ( file[i].size() == 1 )
                    {
                            items.push_back( Point ( atof ( file[i][0].c_str() ) ) );
                    }

                    else if ( file[i].size() == 2 )
                    {
                            items.push_back( Point ( atof ( file[i][0].c_str() ), atof ( file[i][1].c_str() ) ) );
                    }

                    else if ( file[i].size() == 3 )
                    {
                            items.push_back(Point ( atof ( file[i][0].c_str() ), atof ( file[i][1].c_str() ), atof ( file[i][2].c_str() ) ) );
                    }
            }
 }

Если я запускаю эту функцию для 2D-точки, 2D-точка не имеет конструктора с тремя параметрами.Такая же ситуация возникает для 3D-точки ...

List <Point2D> list1;
list1.load("file");  //Error
List <Point3D> list2;
list2.load("file");  //Error

Error   275 error C2661 : no overloaded function takes 3 arguments
Error   275 error C2661 : no overloaded function takes 2 arguments  

Как эффективно разработать такую ​​функцию?Синтаксис несколько упрощен, это только иллюстративный пример.

Ответы [ 4 ]

3 голосов
/ 08 февраля 2011

Мне кажется, я понимаю, в чем ваша проблема: вы пытаетесь создать экземпляр этой функции с помощью класса Point, который имеет (только) конструктор с 1 параметром, ИЛИ класса Point с конструктором с 2 параметрами, ИЛИ класса Point с 3-х параметрическим конструктором. В любом случае вы получите ошибку компилятора о количестве параметров.

Фактически, вы можете создать экземпляр этой функции только с классом Point, который имеет конструктор с 1 параметром И конструктор с 2 параметрами И конструктор с 3 параметрами. Причина в том, что решение о том, какой конструктор вызывать, принимается во время выполнения , основываясь на значении file [i] .size ().

Подумайте об этом: что должно произойти, если вы вызовете эту функцию с классом Point, который имеет только двухпараметрический конструктор, но затем вы встретите строку в файле, где file [i] .size () == 3 ? Какую функцию должен вызывать код?

Чтобы эта функция работала, вам нужно перенести решение о том, какой конструктор вызывать, с времени выполнения на время компиляции. Вы можете сделать это, добавив целочисленный параметр шаблона, который задает размерность и обеспечивает специализации для 1, 2 и 3 измерений. Примерно так может работать:

template <typename Point, int N>
Point construct_point(const vector<string>& line);

template <typename Point>
Point construct_point<Point, 1>(const vector<string>& line)
{
    assert(line.size() == 1);
    return Point(atof ( line[0].c_str() ));
}

template <typename Point>
Point construct_point<Point, 2>(const vector<string>& line)
{
    assert(line.size() == 2);
    return Point(atof ( line[0].c_str() ), atof ( line[1].c_str() ));
}

template <typename Point>
Point construct_point<Point, 3>(const vector<string>& line)
{
    assert(line.size() == 3);
    return Point(atof ( line[0].c_str() ), atof ( line[1].c_str() ), atof ( line[2].c_str() ));
}

template <typename Point>
void List<Point>::load (const char *file)
{
    ...

    for (unsigned i = 0; i < lines.size(); ++i)
    {
         // Assume each Point class declares a static constant integer named 'dimension'
         // which is its dimension.
         items.push_back(construct_point<Point, Point::dimension>(lines[i]));
    }
    ...
}
2 голосов
/ 09 февраля 2011

Я бы порекомендовал вам реализовать оператор >> в ваших точечных классах.

class Point2D {
    int x,y;
public:
    friend istream &operator>> (istream &input, Point2D &pt) {
        return input >> pt.x >> pt.y;
    }
};

class Point3D {
    int x,y,z;
public:
    friend istream &operator>> (istream &input, Point3D &pt) {
        return input >> pt.x >> pt.y >> pt.z;
    }
};

Затем вы можете читать точки из потока if следующим образом:

ifstream input("/tmp/points");
Point2D point2;
Point3D point3;
input >> point2 >> point3;
1 голос
/ 08 февраля 2011

Не беспокойтесь об эффективности при работе с потоками. Узким местом обычно будет чтение и запись с ними, а не обработка, которую вы выполняете до / после.

0 голосов
/ 08 февраля 2011

Вы можете передать число измерений точки в качестве параметра шаблона функции, а затем вызвать list.load<2>("file"). И тогда вы можете специализировать функции для обработки каждого случая ... но, как кто-то отметил, вам не стоит слишком беспокоиться об эффективности.

...