1. 程式人生 > >C++ 函數模板的返回類型如何確定?

C++ 函數模板的返回類型如何確定?

() 真的 指定模板參數 int 報錯 ret space 技術分享 標準庫

函數模板

#include <iostream>


// 多個參數的函數木板                                                                                                                                                                                       
template<typename T1, typename T2>
T2 max(T1 a, T2 b) {

    using namespace std;
    cout << "調用的自定義模板函數...... " << endl;
    return b < a ? a : b;
}


// 顯式指定模板參數的類型                                                                                                                                                                                   
template<typename T>
T max1(T a, T b) {
    using namespace std;
    cout << "顯式指定模板參數...... " << endl;
    return b < a ? a : b;
}


int main() {
    using namespace std;
    double a = ::max(2, 3.2);
    cout << "max(2, 3.2) = " << a << endl;

    double b = ::max1<double>(2, 4);
    cout << "max1<double>(2, 4) = " << b << endl;

    return 0;
}

函數模板有兩種不同類型的參數:

模板參數:在尖括號中聲明的

template<typename T>

調用參數:函數模板名稱的括號中聲明的

T max(T a, T b)

如果使用了多個模板類型參數的話,返回值有時候是個問題,對此有三種方法:

  • 為返回值單獨引入一個模板類型參數
  • 讓編譯器找到返回類型
  • 聲明一個其他類型的共同類型

返回值的模板參數

函數模板可以自動檢測模板參數類型,因此我們可以不同顯式指定,當然顯式指定也可以的。

比如:

#include <iostream>

// 顯式指定模板參數的類型                                                                                                                                                                                   
template<typename T>
T max1(T a, T b) {
    using namespace std;
    cout << "顯式指定模板參數...... " << endl;
    return b < a ? a : b;
}

int main() {
    using namespace std;
    double b = ::max1<double>(2, 4);
    cout << "max1<double>(2, 4) = " << b << endl;
    return 0;
}

在進行 ::max1<double>(2, 4); 調用的時候,就是顯式指定了模板參數。

現在來一個為返回值引入第三個模板參數:RT max(T1 a, T2 b);

#include <iostream>

// 多個參數的函數木板                                                                                                                                                                                       
template<typename T1, typename T2, typename RT>
RT max(T1 a, T2 b) {
    using namespace std;
    cout << "調用的自定義模板函數...... " << endl;
    return b < a ? a : b;
}

int main() {
    using namespace std;
    double a = ::max(2, 3.2);
    cout << "max(2, 3.2) = " << a << endl;
    return 0;
}

然後編譯的時候就報錯了:

技術分享圖片

報錯信息提示:參數 deduction(推理)失敗了

這裏引出了自動推理的規則:

如果模板參數和調用參數的類型沒有什麽關系,那麽在調用的時候 參數模板的所有類型是不能完全確定的,你必須顯式指定模板參數。

因此顯式指定以下就可以了:

#include <iostream>

// 多個參數的函數木板                                                                                                                                                                                       
template<typename T1, typename T2, typename RT>
RT max(T1 a, T2 b) {
    using namespace std;
    cout << "調用的自定義模板函數...... " << endl;
    return b < a ? a : b;
}

int main() {
    using namespace std;
    // 模板參數和調用參數不能完全匹配的時候需要顯式指定                                                                                                                                                     
    double a = ::max<int, double, double>(2, 3.2);
    cout << "max(2, 3.2) = " << a << endl;
    return 0;
}

編譯通過,運行成功。

但是指定所有的模板類型又有點啰嗦,這裏又來了一條規則:

你必須顯式指定直到最後一個不能確定的所有模板類型。

比如上面例子中,RT 的類型是不能通過參數類型推理來確定的,所以導致 T1 和 T2 的類型都要顯式指定。

因此這裏來了一個騷操作,就是把不能指定的模板類型都放在模板參數列表的最前面,那麽後面可以確定的模板參數就可以不用顯式指定了。

#include <iostream>

// 多個參數的函數木板                                                                                                                                                                                       
template<typename RT, typename T1, typename T2>
RT max(T1 a, T2 b) {
    using namespace std;
    cout << "調用的自定義模板函數...... " << endl;
    return b < a ? a : b;
}

int main() {
    using namespace std;
    // 這個 double 專門為了 RT 而指定的, T1 和 T2 都可以通過調用參數推導出來                                                                                                                                
    double a = ::max<double>(2, 3.2);
    cout << "max(2, 3.2) = " << a << endl;
    return 0;
}

我只想說 C++ 是真的騷。

編譯器推理返回類型

如果返回類型依賴於模板參數,那麽最簡單的方法就是讓編譯器去推導類型。

C++ 14 中已經可以不用指定返回類型了,但是你還是要用 auto 來聲明返回類型。

如下面的例子:

#include <iostream>

// 多個參數的函數木板                                                                                                                                                                                       
template<typename T1, typename T2>
auto max(T1 a, T2 b) {
    using namespace std;
    cout << "調用的自定義模板函數...... " << endl;
    return b < a ? a : b;
}

int main() {
    using namespace std;
    // 這個 double 專門為了 RT 而指定的, T1 和 T2 都可以通過調用參數推導出來                                                                                                                                
    auto a = ::max(2, 3.2);
    auto b = ::max(5, 1.2);
    cout << "max(2, 3.2) = " << a << endl;
    cout << "max(5, 1.2) = " << b << endl;
    return 0;
}

大爺的,我又要去學下 auto 是怎麽用的。

使用了 auto 就可以不用 trailing of return type(返回類型後置),但是實際的返回類型還是要通過函數體中的返回語句來推導。

當然了,根據函數體來反推返回值類型要是可行的。

decltype

decay

看到這裏有點懵逼。

公共類型作為返回類型

C++ 11 中,標準庫提供了一種對多個類型生成共同類型的方法。

例如:

#include <iostream>

// 引入這個玩意兒生成共同類型                                                                                                                                                                               
#include <type_traits>


// 騷裏騷氣啊                                                                                                                                                                                               
template<typename T1, typename T2>
std::common_type_t<T1, T2> max(T1 a, T2 b) {
    using namespace std;
    cout << "調用的自定義模板函數...... " << endl;
    return b < a ? a : b;
}

int main() {
    using namespace std;
    // 這個 double 專門為了 RT 而指定的, T1 和 T2 都可以通過調用參數推導出來                                                                                                                                
    auto a = ::max(2, 3.2);
    auto b = ::max(5, 1.2);
    cout << "max(2, 3.2) = " << a << endl;
    cout << "max(5, 1.2) = " << b << endl;
    return 0;
}

std::common_type 是一種 type trait,能夠為返回類型生成一種結構。

typename std::common_type<T1, T2>::type // since C++ 11

而在 C++ 14 中

std::cmmon_type_t<T1, T2> // C++ 14 中的寫法

服!氣!

C++ 函數模板的返回類型如何確定?