3

我想实现一个从文件中加载 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

4 回答 4

3

我想我明白你的问题是什么:你试图用一个 Point 类实例化这个函数,它(只有)一个 1 参数构造函数,或者一个带有 2 参数构造函数的 Point 类,或者一个带有 3 的 Point 类-参数构造函数。无论哪种情况,您都会收到有关参数数量的编译器错误。

实际上,您只能使用具有 1 参数构造函数和 2 参数构造函数和 3 参数构造函数的 Point 类来实例化此函数。原因是调用哪个构造函数的决定是在运行时根据 file[i].size() 的值做出的。

想一想:如果您使用仅具有 2 参数构造函数的 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]));
    }
    ...
}
于 2011-02-08T20:45:30.230 回答
2

我建议你在你的点类中实现一个 operator>>。

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;
    }
};

然后,您可以像这样从 ifstream 中读取点:

ifstream input("/tmp/points");
Point2D point2;
Point3D point3;
input >> point2 >> point3;
于 2011-02-08T21:01:27.240 回答
1

在处理流时不要太担心效率。瓶颈通常是与它们一起读写,而不是在您之前/之后进行的任何处理中。

于 2011-02-08T20:42:48.023 回答
0

您可以将点的维数作为模板参数传递给函数,然后调用list.load<2>("file"). 然后你可以专门处理每种情况的功能......但正如有人指出的那样,你不应该太担心效率。

于 2011-02-08T20:53:04.783 回答