【问题标题】:C++ templates containing std::vector包含 std::vector 的 C++ 模板
【发布时间】:2014-11-09 20:28:26
【问题描述】:

最近我写了一个类,其中包含四个函数来打开和读取多列数据文件(最多 4 列)。在函数中,要打开的文件名“file_name”从主程序传递到类“Read_Columnar_File”中的函数。使用 std::vector 读取数据并传回主程序。但是,它要求程序员在每次使用输入列时都更改其数据类型,这是错误的根源。文件名总是一个字符串,所以不需要模板化;但是,使用 vector 读取的数组的数据类型可能会发生变化,因此需要对其进行通用模板化。我正在尝试将类转换为模板类,并且缺少对制作包含 std::vector 的模板的过程的一些基本理解。为了简化开发过程,我回到了类中名为“Read_One_Column”的单个例程,并尝试将其转换为数据类型标记为 Type1 的模板。我认为我的问题出在语法上,因为调试器告诉我主程序中的命令未定义。任何有助于纠正此问题的建议将不胜感激。现有代码的副本附在下面。

#include <vector>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <iterator>

template <class Type1> class Read_Columnar_File {
public:
    void Read_One_Column(const std::string& file_name,std::vector<Type1>& Column1);
};

template <class Type1> void Read_Columnar_File<Type1>::Read_One_Column(const std::string& file_name,
                                                                       std::vector<Type1>& Column1)
{
    std::ifstream inp(file_name,std::ios::in | std::ios::binary);
    std::istream_iterator<Type1> start((inp)), end;
    if(inp.is_open()) {
    Column1.assign(start,end);
}
    else std::cout << "Cannot Open " << file_name << std::endl;
    inp.close();
}

int main(int argc, const char * argv[]) {
    int i;
    std::vector<float> str1;
    Read_Columnar_File<float> ob1;

    char str[20];
    std::strcpy(str,"Test.txt");

    ob1.Read_One_Column(str,str1);

    for(i=0; i < 7; i++) std::cout << str1[i] << std::endl;

    return 0;
}

【问题讨论】:

    标签: c++ class templates vector


    【解决方案1】:

    语法更简单:

    template <typename Type1>
    void Read_One_Column(const std::string& file_name,
                         std::vector<Type1>& Column1) {
        ...
    }
    

    根本不需要创建一个类(它只是一个模板函数)。

    如果出于其他原因需要将函数放入类中,则语法相同

    struct Read_Columnar_File {
        ...
        template<typename Type1>
        void Read_One_Column(const std::string& file_name,
                             std::vector<Type1>& Column1) {
            ...
        }
    }
    

    它将是类的模板方法。

    【讨论】:

    • 我想这是一个很好的观点。完成后,该类将包含四个函数,而不仅仅是一个,所以我将它写到一个类中,作为将它们组织在一起的一种方法。但是,由于属性可能永远不需要应用继承或多态性,并且一个函数不依赖另一个函数,因此出于组织目的将四个函数写入同一个文件而不是将它们放在一个类中可能会更好。
    • 但是,无论它是如何编写的,我仍然会收到以下错误。 "Read_Columnar_File::Read_One_Column(std::__1::basic_string, std::__1::allocator > const&, std::__1::vector >&)”,引用自:main.o 中的 _main ld:未找到架构 x86_64 的符号:错误:链接器命令失败,退出代码为 1(使用-v 查看调用)
    • @jon:你知道模板必须在标头中实现还是必须显式实例化?
    • 您能否进一步扩展,我不确定您的意思。在上面列出的示例中,模板在标头中声明。此外,虽然我提供的示例没有更改,但我确实成功编写了一个简单示例,该示例不涉及具有上述相同标头格式的向量。
    • @jon: 在标题中声明模板是不够的,您还必须定义它(即提供实现),否则编译器将假定程序中使用的所有模板参数组合的某些编译单元实际上将显式实例化主体(仅在编译单元中提供实现是不够的)。除非您遇到特定问题(例如,实现的大量依赖项),否则最简单的方法是将所有内容放在标题中。
    【解决方案2】:

    为了完全解决这个问题,我发布了最终且正确的代码,因为我相信其他人将来也会有同样的问题,我希望这对他们有所帮助。为了回答我的问题,在编写模板时,整个算法需要包含在头文件中,并且不能在头文件和实现文件之间拆分。该程序旨在成为一种从输入文件中读取列数据的非常通用的方法,并假设每列数据的长度与其他列相同。用户只需将头文件添加到他们的主程序中,在向量定义中指定每一列的数据类型并读入数据。主程序如下所示。此版本允许用户调用 4 个不同的函数,这些函数可用于读取多达四列数据。

        #include <vector>
        #include <iostream>
        #include <cstring>
        #include "Read_Columnar_File.h"
    
        int main(int argc, const char * argv[]) {
            char str[20];
            strcpy(str,"Test.txt");
    
            // - Format for reading in a single column of data
            //   Data in this case is declared as a float in
            //   the vector, but it can be any data type
            /*
            std::vector<float> str2;
            Read_One_Column(str,str2);
            */
    
            // - Format for reading in two columns of data from
            //   an input file
            /*
            std::vector<float> str2;
            std::vector<int> str3;
            Read_Two_Columns(str,str2,str3);
             */
    
            // - Format for reading in three columns of data from
            //   an input file
            /*
            std::vector<float> str2;
            std::vector<int> str3;
            std::vector<int> str4;
            Read_Three_Columns(str,str2,str3,str4);
             */
    
            std::vector<float> str2;
            std::vector<int> str3;
            std::vector<int> str4;
            std::vector<float> str5;
            Read_Four_Columns(str,str2,str3,str4,str5);
    
            return 0;
        }
    
    The implementation file is shown below.
    
        #include <vector>
        #include <stdio.h>
        #include <fstream>
        #include <iterator>
    
        template <class X> void Read_One_Column(const std::string& file_name,std::vector<X>& Column1)
        {
            std::ifstream inp(file_name,std::ios::in | std::ios::binary);
            std::istream_iterator<X> start((inp)), end;
            if(inp.is_open()) {
                Column1.assign(start,end);
            }
            else std::cout << "Cannot Open " << file_name << std::endl;
            inp.close();
        }
    
        template <class X,class Y> void Read_Two_Columns(const std::string& file_name,std::vector<X>& Column1,
                                                std::vector<Y>& Column2)
        {
            int i;
            X Col1;
            Y Col2;
            std::ifstream inp(file_name,std::ios::in | std::ios::binary);
            if(inp.is_open()){
            for(i=0; i < 7; i++){
                    inp >> Col1 >> Col2;
                    Column1.push_back(Col1), Column2.push_back(Col2);
                }
            }
            else std::cout << "Cannot Open " << file_name << std::endl;
            inp.close();
         }
    
        template <class X,class Y, class Z> void Read_Three_Columns(const std::string& file_name,std::vector<X>& Column1,
                                                                    std::vector<Y>&     Column2,std::vector<Z>& Column3
        {
            int i;
            X Col1;
            Y Col2;
            Z Col3;
            std::ifstream inp(file_name,std::ios::in | std::ios::binary);
        if(inp.is_open()){
            for(i=0; i < 7; i++){
                inp >> Col1 >> Col2 >> Col3;
                Column1.push_back(Col1), Column2.push_back(Col2), Column3.push_back(Col3);
            }
        }
        else std::cout << "Cannot Open " << file_name << std::endl;
        inp.close();
    }
    
    template <class X,class Y, class Z,class A> void Read_Four_Columns(const std::string& file_name,std::vector<X>& Column1,
                                                                std::vector<Y>& Column2,std::vector<Z>& Column3,
                                                                std::vector<A>& Column4)
    {
        int i;
        X Col1;
        Y Col2;
        Z Col3;
        A Col4;
        std::ifstream inp(file_name,std::ios::in | std::ios::binary);
        if(inp.is_open()){
            for(i=0; i < 7; i++){
                inp >> Col1 >> Col2 >> Col3 >> Col4;
                Column1.push_back(Col1), Column2.push_back(Col2),
                Column3.push_back(Col3), Column4.push_back(Col4);
            }
        }
        else std::cout << "Cannot Open " << file_name << std::endl;
        inp.close();
    }
    

    【讨论】:

      猜你喜欢
      • 2013-05-07
      • 1970-01-01
      • 2014-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多