函數的二義性與函數對象的傳遞問題(通過實現vector的to_string示例)

許多時候,我們想要直接打印容器的內容,比如

std::vector<int> a = { 1, 2, 3 };

可以打印出[1, 2, 3]。

?

參考標準庫,可以寫出一個帶有迭代器的to_string函數:

template <typename Iter, typename Func>
std::string to_string(Iter begin, Iter end, Func func) {std::string str;str.append("[");if (begin != end) {str.append(func(*begin++));while (begin != end) {str.append(", ");str.append(func(*begin++));}}str.append("]");return str;
}

在調用時候,可以直接傳入begin()和end(),作為迭代器,再傳入對于元素的to_string函數,即可實現容器的to_string。

std::to_string是C++11新增的標準庫中定義的函數,具有多個重載函數(詳情請參考to_string - C++Reference):

string to_string (int val);
string to_string (long val);
string to_string (long long val);
string to_string (unsigned val);
string to_string (unsigned long val);
string to_string (unsigned long long val);
string to_string (float val);
string to_string (double val);
string to_string (long double val);

由于是重載函數,因此不能直接使用名稱to_string進行函數的傳遞。

我們想要使用類似于to_string(vec.begin(), vec.end(), to_string)這種傳遞方式,怎么辦呢?

?

在C++11中,我們可以傳遞匿名函數(lambda)解決二義性問題:

用 [](const T &t) { return to_string(t); } 取代?to_string。

to_string(vec.begin(), vec.end(), [](const T &t) { return to_string(t); });

還有一種方法,就是定義函數對象:

template <typename T>
struct ToString
{std::string operator()(const T &t){return to_string(t);}
};

to_string(vec.begin(), vec.end(), ToString<T>());

這在C++11標準之前的代碼中經常使用。

?

借此,我們可以定義一個vector版的to_string函數:

template <typename T>
std::string to_string(const std::vector<T> &vec)
{return to_string(vec.begin(), vec.end(),[](const T &t) { return to_string(t); });
}
// Or
template <typename T>
std::string to_string(const std::vector<T> &vec)
{return to_string(vec.begin(), vec.end(), ToString<T>());
}

然后,就可以這么使用了:

	std::vector<int> a = { 1, 2, 3 };std::vector<int> b = { 4, 5, 6 };std::vector<std::vector<int>> c = { a, b };std::cout << to_string(a) << std::endl; // [1, 2, 3]std::cout << to_string(b) << std::endl; // [4, 5, 6]std::cout << to_string(c) << std::endl; // [[1, 2, 3], [4, 5, 6]]

可以輸出vector的各種類型(包括vector)。

?

然而,存在一個問題就是,由于我的這些代碼在最初就using namespcae std;了,因此并沒有什么問題出現(很好地實現了vector類型的to_string重載)。

但是,當我們把該行去掉后,就會發現,編譯器會報出錯誤。

比如在ToString類的operator()函數中,在

return to_string(t);

這一行,就報出了:

error: no matching function for call to 'to_string(const int&)'

的錯誤。

似乎解決方法很簡單,直接加std::不就行了嗎?

然而,我們發現,這種解決方法,在只輸出a和b的情況下,確實沒什么問題,但是,當輸出c的時候,又報出了

error: no matching function for call to 'to_string(const std::vector<int>&)'

的錯誤。

——怎么辦呢?

其實解決起來很簡單,就是使用using使得命名空間無效,當然這個using是加在函數里面的。

template <typename T>
struct ToString
{std::string operator()(const T &t){using std::to_string; // 標準庫to_stringusing ::to_string;    // 自定義to_stringreturn to_string(t);}
};

using ::to_string表示你自定義to_string的位置,如果也是在命名空間里面,如(namespace A),那么就寫成using A::to_string;即可。

?

完整代碼如下:

#include <iostream>
#include <string>
#include <vector>template <typename Iter, typename Func>
std::string to_string(Iter begin, Iter end, Func func) {std::string str;str.append("[");if (begin != end) {str.append(func(*begin++));while (begin != end) {str.append(", ");str.append(func(*begin++));}}str.append("]");return str;
}template <typename T>
struct ToString;template <typename T>
std::string to_string(const std::vector<T> &vec)
{return to_string(vec.begin(), vec.end(), ToString<T>());// Or/*return to_string(vec.begin(), vec.end(),[](const T &t) {using std::to_string;using ::to_string;return to_string(t);});*/
}template <typename T>
struct ToString
{std::string operator()(const T &t){using std::to_string;using ::to_string;return to_string(t);}
};int main(void)
{std::vector<int> a = { 1, 2, 3 };std::vector<int> b = { 4, 5, 6 };std::vector<std::vector<int>> c = { a, b };std::cout << to_string(c) << std::endl;return 0;
}

?

轉載于:https://www.cnblogs.com/chillmagic/p/5713773.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/458204.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/458204.shtml
英文地址,請注明出處:http://en.pswp.cn/news/458204.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

libSVM介紹(二)

from&#xff1a;https://blog.csdn.net/carson2005/article/details/6539192 鑒于libSVM中的readme文件有點長&#xff0c;而且&#xff0c;都是采用英文書寫&#xff0c;這里&#xff0c;我把其中重要的內容提煉出來&#xff0c;并給出相應的例子來說明其用法&#xff0c;大家…

四則運算題2

本題新學知識點&#xff1a; itoa函數 char *itoa( int value, char *string,int radix);[1]原型說明&#xff1a;value&#xff1a;欲轉換的數據。string&#xff1a;目標字符串的地址。radix&#xff1a;轉換后的進制數&#xff0c;可以是10進制、16進制等。程序實例:#includ…

c++調用Libsvm

libSVM中的readme中文版&#xff1a;http://blog.csdn.net/carson2005/article/details/6539192 LibSVM的package中的Readme文件中介紹了怎樣具體的使用LibSvm&#xff0c;可以在Dos下以命令形式進行調用&#xff0c;也可以用程序包中提供的GUI程序Svm-toy進行圖形化的操作。sv…

STL -set

轉載自&#xff1a;http://blog.csdn.net/LYHVOYAGE/article/details/22989659 set集合容器實現了紅黑樹&#xff08;Red-Black Tree&#xff09;的平衡二叉檢索樹的的數據結構&#xff0c; 在插入元素時&#xff0c;它會自動調整二叉樹的排列&#xff0c;把該元素放到適當的位…

【機器學習實戰之一】:C++實現K-近鄰算法KNN

本文不對KNN算法做過多的理論上的解釋&#xff0c;主要是針對問題&#xff0c;進行算法的設計和代碼的注解。 KNN算法&#xff1a; 優點&#xff1a;精度高、對異常值不敏感、無數據輸入假定。 缺點&#xff1a;計算復雜度高、空間復雜度高。 適用數據范圍&#xff1a;數值…

libsvm C++ 代碼參數說明匯總

幾個重要的數據結構 2.1 struct svm_problem {int l; // 記錄樣本的總數double *y; // 樣本所屬的標簽(1, -1)struct svm_node **x; // 指向樣本數據的二維數組(即一個矩陣&#xff0c;行數是樣本數&#xff0c;列數是特征向量維度) }; 2.2 struct svm_node {int …

javascript設計模式-繼承

javascript繼承分為兩種&#xff1a;類式繼承&#xff08;原型鏈、extend函數&#xff09;、原型式繼承&#xff08;對繼承而來的成員的讀和寫的不對等性、clone函數&#xff09;。 類式繼承-->prototype繼承&#xff1a; 1 function Person(name){2 this.name …

GIS基礎軟件及操作(二)

原文 GIS基礎軟件及操作(二) 練習二、管理地理空間數據庫 1.利用ArcCatalog 管理地理空間數據庫 2.在ArcMap中編輯屬性數據 第1步 啟動 ArcCatalog 打開一個地理數據庫 當 ArcCatalog打開后&#xff0c;點擊, 按鈕&#xff08;連接到文件夾&#xff09;. 建立到包含練習數據的…

libSVM分類小例C++

from&#xff1a;http://www.doczj.com/list_31/ 使用libSVM求解分類問題的C小例 1.libSVM簡介 訓練模型的結構體 struct svm_problem//儲存參加計算的所有樣本 { int l; //記錄樣本總數 double *y; //指向樣本類別的組數 //prob.y new double[prob.l]; struct svm_node …

qunit 前端腳本測試用例

首先引用qunit 測試框架文件 <link rel"stylesheet" href"qunit-1.22.0.css"> <script src"qunit-1.22.0.js"></script> <div id"qunit"></div> <div id"qunit-fixture"></div>…

非常規文件名刪除

生活中我們偶爾會遇到這樣一件事&#xff1a;走在路上&#xff0c;突然感覺鞋底有東西&#xff0c;抬腳一看&#xff0c;是個泡泡糖。拿不掉&#xff0c;走路還一粘一粘的。要多難受有多難受&#xff01;同樣在linux中也有這么一種文件名。看著不舒服&#xff0c;卻刪不掉。今天…

Machine Learning(Stanford)| 斯坦福大學機(吳恩達)器學習筆記【匯總】

from&#xff1a;https://blog.csdn.net/m399498400/article/details/52556168 定義本課程常用符號 訓練數據&#xff1a;機器用來學習的數據 測試數據&#xff1a;用來考察機器學習效果的數據&#xff0c;相當于考試。 m 訓練樣本的數量&#xff08;訓練集的個數) x 輸入的…

PHP OOP

類跟對象的關系類是對象的抽象(對象的描述(屬性)&#xff0c;對象的行為(方法))對象是類的實體面相對象的三大特征&#xff1a;封裝、集成、多態自定義類Class Person{}屬性定義屬性是類里面的成員&#xff0c;所以要定義屬性的前提條件是需要聲明一個類Class Person{public $n…

kv存儲對抗關系型數據庫

http://www.searchdatabase.com.cn/showcontent_52657.htm轉載于:https://www.cnblogs.com/hexie/p/5276034.html

模板匹配算法

from&#xff1a;https://blog.csdn.net/zhi_neng_zhi_fu/article/details/51029864 模板匹配(Template Matching)算法 模板匹配&#xff08;Template Matching&#xff09;是圖像識別中最具代表性的方法之一。它從待識別圖像中提取若干特征向量與模板對應的特征向量進行比較…

關于linux用戶權限的理解

創建用戶useradd 用戶名創建用戶組groupadd 組名查看用戶Idid 用戶修改文件權限chmod 777 文件名或目錄-R 遞歸修改用戶數組chown 屬主&#xff1a;屬組 文件名或目錄名-R 遞歸轉載于:https://blog.51cto.com/1979431/1833512

IMEI串號

IMEI串號就是國際移動設備身份碼&#xff0c;是電子設備的唯一身份證&#xff0c;由于它的唯一性&#xff0c;它可以用來查詢電子設備的保修期還有產地&#xff0c;可以說用處直逼人民的身份證啊&#xff01; 在撥號鍵盤頁面 輸入【*#06#】五個字符轉載于:https://www.cnblogs…

立體匹配十大概念綜述---立體匹配算法介紹

from&#xff1a;https://blog.csdn.net/wintergeng/article/details/51049596 一、概念 立體匹配算法主要是通過建立一個能量代價函數&#xff0c;通過此能量代價函數最小化來估計像素點視差值。立體匹配算法的實質就是一個最優化求解問題&#xff0c;通過建立合理的能量函數…

zjnu1730 PIRAMIDA(字符串,模擬)

Description Sample Input 6 JANJETINA 5 1 J 1 A 6 N 6 I 5 E Sample Output 1 0 2 1 1題意&#xff1a;給你一個長度小于等于10^6的字符串&#xff0c;然后每次讓它循環鋪蓋&#xff0c;構成層數為n的塔&#xff0c;讓你求得第i層塔中某個字符的個數。 思路&#xff1a;首先要…

ICP算法理解

from&#xff1a;https://blog.csdn.net/linear_luo/article/details/52576082 1 經典ICP ICP的目的很簡單&#xff0c;就是求解兩堆點云之間的變換關系。怎么做呢&#xff1f;思路很自然&#xff0c;既然不知道R和t(針對剛體運動)&#xff0c;那我們就假設為未知量唄&#xf…