C++模板,高效的加载点功能

发布于 2024-10-16 08:39:13 字数 1289 浏览 3 评论 0原文

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

如何高效地设计这样的功能?语法有些简化,这只是一个说明性示例。

I would like to implement a function loading 1D/2D/3D points from file... The template parameter Point can be a 1D 2D 3D point.

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

If I run this function for 2D point, 2D point does not have constructor with three parameters. The same situation occurs for 3D point...

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  

How to design such a function efficiently? The syntax is somewhat simplified, it is only an illustrative example.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

香橙ぽ 2024-10-23 08:39:13

我想我明白你的问题是什么:你试图用一个 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]));
    }
    ...
}

I think I see what your problem is: you're trying to instantiate this function with a Point class which has (only) a 1-parameter constructor, OR a Point class with a 2-parameter constructor, OR a Point class with a 3-parameter constructor. In either case, you get a compiler error about the number of parameters.

In fact, you can only instantiate this function with a Point class that has a 1-parameter constructor AND a 2-parameter constructor AND a 3-parameter constructor. The reason is that the decision of which constructor to call is made at runtime, based on the value of file[i].size().

Think about it: what should happen if you call this function with a Point class that only has a 2-parameter constructor, but then you come across a line in the file where file[i].size() == 3? What function should the code call?

In order to get this function to work, you need to move the decision of which constructor to call from being at runtime to being at compile time. You can do this by adding an integer template parameter that specifies the dimensionality and providing specializations for 1, 2, and 3 dimensions. Something like this might work:

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]));
    }
    ...
}
浅笑轻吟梦一曲 2024-10-23 08:39:13

我建议你实现一个运算符>>在你的积分课程中。

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;

I would recommend you to implement an operator>> in your point classes.

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

Then, you could read points from an ifstream like this:

ifstream input("/tmp/points");
Point2D point2;
Point3D point3;
input >> point2 >> point3;
月牙弯弯 2024-10-23 08:39:13

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

Don't worry too much about efficiency when dealing with streams. The bottleneck is generally going to be reading and writing with them, not in any processing you do before/after.

咆哮 2024-10-23 08:39:13

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

You could pass the number of dimensions of the point as a template parameter to the function, and then call list.load<2>("file"). And then you can specialize the functions to handle each case... but as someone pointed out, you shouldn't worry too much about efficiency.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文