[英]std::function as template parameter
我目前有一個map<int, std::wstring>
,但為了靈活性,我希望能夠分配一個lambda表達式,在地圖中返回std::wstring
作為值。
所以我創建了這個模板類:
template <typename T>
class ValueOrFunction
{
private:
std::function<T()> m_func;
public:
ValueOrFunction() : m_func(std::function<T()>()) {}
ValueOrFunction(std::function<T()> func) : m_func(func) {}
T operator()() { return m_func(); }
ValueOrFunction& operator= (const T& other)
{
m_func = [other]() -> T { return other; };
return *this;
}
};
並使用它像:
typedef ValueOrFunction<std::wstring> ConfigurationValue;
std::map<int, ConfigurationValue> mymap;
mymap[123] = ConfigurationValue([]() -> std::wstring { return L"test"; });
mymap[124] = L"blablabla";
std::wcout << mymap[123]().c_str() << std::endl; // outputs "test"
std::wcout << mymap[124]().c_str() << std::endl; // outputs "blablabla"
現在,我不想使用構造函數來包裝lambda,所以我決定添加第二個賦值運算符,這次是std::function
:
ValueOrFunction& operator= (const std::function<T()>& other)
{
m_func = other;
return *this;
}
這是編譯器開始抱怨的地方。 線mymap[124] = L"blablabla";
突然導致這個錯誤:
錯誤C2593:'operator = is ambiguous'
IntelliSense提供了更多信息:
多個運算符“=”匹配這些操作數:function“ValueOrFunction :: operator =(const std :: function&other)[with T = std :: wstring]”function“ValueOrFunction :: operator =(const T&other)[with T = std :: wstring]“操作數類型是:ConfigurationValue = const wchar_t [10] c:\\ projects \\ beta \\ CppTest \\ CppTest \\ CppTest.cpp 37 13 CppTest
所以,我的問題是,為什么編譯器能夠區分std::function<T()>
和T
? 我該如何解決這個問題?
基本問題是std::function
有一個貪婪的隱式構造函數,它會嘗試轉換任何東西 ,而且只能在正文中編譯。 因此,如果你想重載它,或者不允許轉換為替代方案,你需要禁用可以轉換為替代方法來調用std::function
重載的東西。
最簡單的技術是標簽調度。 使operator=
貪婪並設置為完美轉發,然后手動調度到帶有標記的assign
方法:
template<typename U>
void operator=(U&&u){
assign(std::forward<U>(u), std::is_convertible<U, std::wstring>());
}
void assign(std::wstring, std::true_type /*assign_to_string*/);
void assign(std::function<blah>, std::false_type /*assign_to_non_string*/);
基本上我們正在做手動重載決議。
更先進的技術:(可能不需要)
另一種方法是限制std::function
=
SFINAE對被調用的參數是有效的,但這更加混亂。
如果你有多種不同的類型與你的std::function
競爭,你不得不遺憾地手動調度所有這些類型。 解決這個問題的方法是測試你的類型U
是否可以無需調用,結果可以轉換為T
,然后標記為dispatch。 將非std::function
重載粘貼在備用分支中,讓其他一切通常更傳統的重載。
有一個細微的區別在於,一個可轉換為std::wstring
和callable的std::wstring
返回可轉換為T
東西,最終被分派到不同於上述原始簡單解決方案的重載,因為所使用的測試實際上並不是互斥的。 對於C ++重載的完全手動模擬(針對std::function
s stupidity進行了更正),你需要使這種情況模糊不清!
最后一個高級操作是使用auto
和尾隨返回類型來提高其他代碼檢測您的=
是否有效的能力。 就個人而言,我不會在C ++ 14之前做到這一點,除非在脅迫之下,除非我正在編寫一些嚴肅的庫代碼。
std::function
和std::wstring
都有轉換運算符,可以使用你傳遞的文字寬字符串。 在這兩種情況下,轉換都是用戶定義的,因此轉換序列具有相同的優先級,從而導致歧義。 這是錯誤的根本原因。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.