對於和std::vector
的operator<<
過載,我無法使用標準中指定的(正確)clang實施的兩相查找。使用通用模板函數專門化運算符<<用於std :: ostream和std :: vector的最佳方法?
考慮其轉移參數轉化爲流一個非常通用的模板函數(實際上只用遞歸是有用的,但簡單的例子就足以引發問題):
// generic.h
template<typename Stream, typename Arg>
void shift(Stream& s, Arg& arg) { s << arg; }
這generic.h可使用整個項目。然後,在一些其他文件中,我們要輸出一個std::vector
,所以我們定義一個過載
// vector.h
#include <iostream>
#include <vector>
std::ostream& operator<<(std::ostream& s, std::vector<int> const& v) {
for(auto const& elem : v) { s << elem << ", "; }
return s;
}
和主文件中,我們首先(間接地)使用generic.h
,然後,由於一些其它包括,載體過載:
// main.cpp
#include "generic.h"
#include "vector.h"
int main() {
std::vector<int> v{1,2,3,4,5};
shift(std::cout, v);
}
此代碼由GCC(5.4.0)和ICC(16.0)接受,但鐺抱怨call to function 'operator<<' that is neither visible in the template definition nor found by argument-dependent lookup
。
惱人的是,鏗鏘是對的,我想解決這個問題在我的代碼。還有據我可以看到三個選項:
移動的
operator<<
定義shift()
之前。這具有的缺點是,當包括間接包括generic.h
和vector.h
的一些(可能是其他)文件時,還必須小心地對它們進行正確排序。使用自定義名稱空間,將所需的所有內容從
std
導入該名稱空間,並在名稱空間內的新名稱空間類上定義運算符,以便ADL可以找到它。在
std
命名空間中定義operator<<
。我認爲這是未定義的行爲。
我錯過任何選項嗎?一般來說,定義std
函數的重載最好的方法是什麼 - 只有類(如果我想移動NS::MyClass
,則不存在問題,因爲我可以在NS
中定義運算符)。
如果你要使用指針,你可能應該檢查'nullptr'。否則,只需使用參考或可選類型 – KABoissonneault
是的。很顯然,可以進行調整,具體取決於你想要如何使用它或者想要如何防守。引用的缺點是類型不可分配。如果這沒關係,那麼請使用參考。答案的要點是「使用適配器而不是爲不屬於你的類型重載操作符」,而不是「如何編寫適合所有人的通用適配器」。 –
重新引用不可分配引用的缺點:使用如此輕量級的包裝器,您可以隨時重新創建一個,因此我同意@KABoissonneault使用引用而不是指針。 – TemplateRex