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 ポイントには 3 つのパラメーターを持つコンストラクターがありません。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

私はあなたの問題が何であるかを理解していると思います.1パラメーターのコンストラクターを持つ(のみ)Pointクラス、または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 に答える