2012-05-13 103 views
1

我正在閱讀一本書(Accelerated C++)並從那本試圖通過自己學習C++的書中鍛鍊身體。模板,爲什麼用這種方式調用模板函數不起作用?

現在我想明白爲什麼下面這段代碼不工作:

// analysis.cpp 
void write_analysis(ostream& out, const string& name, 
        double analysis(const vector<Student_info>&), 
        const vector<Student_info>& did, 
        const vector<Student_info>& didnt) 
{ 
    out << name << ":median(did) = " << analysis(did) << 
    ", median(didnt)=" << analysis(didnt) << endl; 
} 

template <double F(Student_info&)> 
double generic_analysis(const vector<Student_info>& students) 
{ 
    vector<double> grades; 

    transform(students.begin(), students.end(), 
      back_inserter(grades), F); 
    return median(grades); 
} 
template<> double generic_analysis<grade_aux>(const vector<Student_info>& students); 

double median_analysis(const vector<Student_info>& students) 
{ 
    return generic_analysis<grade_aux>(students); 
    // if not using template function, the code will be 
    // as following 
    // vector<double> grades; 

    // transform(students.begin(), students.end(), 
    //   back_inserter(grades), grade_aux); 
    // return median(grades); 
} 

analysis.cpp

// analysis.h 
template <double F(const Student_info&)> 
double generic_analysis(const std::vector<Student_info>&); 

void write_analysis(std::ostream&, const std::string&, 
        double analysis(const std::vector<Student_info>&), 
        const std::vector<Student_info>&, 
        const std::vector<Student_info>&); 

double grade_aux(const Student_info&); 

double median_analysis(const std::vector<Student_info>&); 

analysis.h

// main.cpp 
int main() 
{ 
    // students who did and didn't do all their homework 
    vector<Student_info> did, didnt; 

    // read the student records and partition them 
    Student_info student; 
    while (read(cin, student)) { 
    did.push_back(student); 
    } 

    // do the analyses 
    write_analysis(cout, "median", median_analysis, did, didnt); 

    return 0; 
} 

爲主。 cpp

// grade.cpp 
// compute a student's overall grade from midterm and final exam grades 
// and homework grade 
double grade(double midterm, double final, double homework) 
{ 
    return 0.2 * midterm + 0.4 * final + 0.4 * homework; 
} 

double grade_aux(const Student_info& s) 
{ 
    try { 
    return grade(s); 
    } catch (domain_error) { 
    return grade(s.midterm, s.final, 0); 
    } 
} 

grade.cpp

和錯誤消息是:

g++ -Wall *.cpp -o main /tmp/ccbXbVcV.o: In function median_analysis(std::vector<Student_info, std::allocator<Student_info> > const&)': analysis.cpp:(.text+0x91): undefined reference to double generic_analysis<&(grade_aux(Student_info const&))>(std::vector > const&)' collect2: ld returned 1 exit status

同時,當我把generic_analysis代碼聲明並定義頭文件, 它會在裏面工作。請有人解釋爲什麼?

編輯: 當刪除行:

template<> double generic_analysis<average_grade>(const vector<Student_info>& students); 

我:

g++ -Wall *.cpp -o main /tmp/cc3VhXKU.o: In function median_analysis(std::vector<Student_info, std::allocator<Student_info> > const&)': analysis.cpp:(.text+0x91): undefined reference to double generic_analysis<&(grade_aux(Student_info const&))>(std::vector > const&)' collect2: ld returned 1 exit status

所以好像我需要一個Explicit instantiation。然後我添加了下面一行:

template double generic_analysis<grade_aux>(const vector<Student_info>&); 

現在的錯誤信息是:

g++ -Wall *.cpp -o main

analysis.cpp: In instantiation of ‘double generic_analysis(const std::vector&) [with double (* F)(const Student_info&) = grade_aux]’:

analysis.cpp:26:72: instantiated from here analysis.cpp:26:72: error: explicit instantiation of ‘double generic_analysis(const std::vector&) [with double (* F)(const Student_info&) = grade_aux]’ but no definition available [-fpermissive] analysis.cpp: In instantiation of ‘double generic_analysis(const std::vector&) [with double (* F)(const Student_info&) = grade_aux]’:

analysis.cpp:26:72: instantiated from here analysis.cpp:26:72: error: explicit instantiation of ‘double generic_analysis(const std::vector&) [with double (* F)(const Student_info&) = grade_aux]’ but no definition available [-fpermissive] analysis.cpp: In instantiation of ‘double generic_analysis(const std::vector&) [with double (* F)(const Student_info&) = grade_aux]’:

analysis.cpp:26:72: instantiated from here analysis.cpp:26:72: error: explicit instantiation of ‘double generic_analysis(const std::vector&) [with double (* F)(const Student_info&) = grade_aux]’ but no definition available [-fpermissive]

+1

明確地實例化模板可能比結果值得更麻煩,因爲'generic_analysis'和'grade_aux'生活在不同的TU中,試圖用後者實例化前者肯定是痛苦的。我推薦你將類似'generic_analysis'這樣的函數模板的定義放在頭文件中,就像習慣使用模板一樣。 –

回答

1

您定義:

template<> double generic_analysis<grade_aux>(const vector<Student_info>& students); 

在哪裏實現?

如果你想實例函數:

http://publib.boulder.ibm.com/infocenter/macxhelp/v6v81/index.jsp?topic=%2Fcom.ibm.vacpp6m.doc%2Flanguage%2Fref%2Fclrc16explicit_instantiation.htm

+0

線以上?還編輯添加「grade_aux' –

+1

@pstar沒有,一旦你聲明的模板函數的專業化必須實現它。 – Anycorn

+0

現在的問題是如何執行的模板功能專業化? –

1

你宣佈

template<> double generic_analysis<grade_aux>(const vector<Student_info>& students); 

,但沒有在任何地方定義它。如果你真的打算有這樣一個明確的專業化,你需要定義它(可能不是在頭上)。

如果另一方面意圖是主模板generic_analysis被使用,那麼你不需要聲明上述特殊性。

+0

我認爲這行是爲了編譯器,所以它可以鏈接模板定義及其實現,否則它不會編譯。我的意圖是使用'generic_analysis'來處理'median_analysis' –

+0

@pstar我建議你嘗試沒有聲明然後。 –