[英]Type trait to check if istream operator>> exists for given type
我發現這種類型特征可以用來檢查某個類型T
是否支持operator<<
:
template<class Class>
struct has_ostream_operator_impl {
template<class V>
static auto test(V*) -> decltype(std::declval<std::ostream>() << std::declval<V>());
template<typename>
static auto test(...) -> std::false_type;
using type = typename std::is_same<std::ostream&, decltype(test<Class>(0))>::type;
};
template<class Class>
struct has_ostream_operator : has_ostream_operator_impl<Class>::type {};
來源: https://gist.github.com/szymek156/9b1b90fe474277be4641e9ef4666f472
這工作正常。 現在我正在嘗試使用 c++11 為operator>>
做同樣的事情,但我沒有讓它工作:
template<class Class>
struct has_istream_operator_impl {
template<class V>
static auto test(V*) -> decltype(std::declval<V>() >> std::declval<std::istream>());
template<typename>
static auto test(...) -> std::false_type;
using type = typename std::is_same<std::istream&, decltype(test<Class>(0))>::type;
};
/**
* @brief Type trait to check if operator>>(std::istream, Type) is defined for a given type.
*/
template<class Class>
struct has_istream_operator : has_istream_operator_impl<Class>::type {};
這是我的用例的簡化測試:
#include <sstream>
#include <type_traits>
#include <iostream>
// <include snippet 2>
template<typename T>
typename std::enable_if<has_istream_operator<T>::value, T>::type
fromString(const std::string& str) {
T value;
std::istringstream stream(str);
stream >> value;
return value;
}
int main() {
std::cout << fromString<long>("123") + 1 << std::endl; // expecting 124
return 0;
}
錯誤是:
has_istream_operator.cpp: In function ‘int main()’:
has_istream_operator.cpp:57:38: error: no matching function for call to ‘fromString<long int>(const char [4])’
std::cout << fromString<long>("123") + 1 << std::endl; // expecting 124
^
has_istream_operator.cpp:49:1: note: candidate: ‘template<class T> typename std::enable_if<has_istream_operator<Class>::value, T>::type fromString(const string&)’
fromString(const std::string& str) {
^~~~~~~~~~
has_istream_operator.cpp:49:1: note: template argument deduction/substitution failed:
has_istream_operator.cpp: In substitution of ‘template<class T> typename std::enable_if<has_istream_operator<Class>::value, T>::type fromString(const string&) [with T = long int]’:
has_istream_operator.cpp:57:38: required from here
has_istream_operator.cpp:49:1: error: no type named ‘type’ in ‘struct std::enable_if<false, long int>’
據我了解,SFINAE 條件為假,因此不存在fromString
的定義。
我嘗試過的是玩這條線
static auto test(V*) -> decltype(std::declval<V>() >> std::declval<std::istream>());
在我對struct has_istream_operator_impl
的定義中。
這是對我來說最有意義的變化,因為當我使用 operator>> 時,我通常這樣做: stream >> value
例如,根據我的(有限)理解, test(V*)
應該測試這個一般對於V
:
static auto test(V*) -> decltype(std::declval<std::istream>() >> std::declval<V>());
但它也不起作用(同樣的錯誤)。
如何讓我這個工作?
長話短說,你應該改變
static auto test(V*) -> decltype(std::declval<V>() >> std::declval<std::istream>());
至
static auto test(V*) -> decltype(std::declval<std::istream>() >> std::declval<V&>());
由於以下原因,代碼中有兩個錯誤。
>>
運算符將 ZF7B44CFFAFD5C52223D5498196C8A2E7BZ 作為第一個參數,而不是作為第二個參數,而您將兩個 arguments 反過來傳遞。declval<V>()
正在生成一個右值(嗯,不是真正的值,因為我們處於未評估的上下文中),您無法通過>>
為其分配值(就像您不能cin >> 123;
),因此您必須將其更改為declval<V&>()
.(¹) ¹要更深入地了解為什么會這樣,請查看cppreference 上的文檔頁面中顯示的std::declval
的可能實現:如您所見,它返回類型typename std::add_rvalue_reference<T>::type
(順便說一句,由於 C++14可以寫為std::add_rvalue_reference_t<T>
),即std::declval<T>()
返回T&&
,即(通過引用折疊)
std::declval
提供左值引用T
(例如std::declval<int&>()
),則為左值引用,std::declval<int>()
)。 在您的用例中,您將T
傳遞給std::declval
,所以我們處於第二種情況,即std::declval<long>()
long
long&&
。 從值類別頁面中,您可以看到 xvalue 的示例(就像純右值、右值一樣)如下(我的重點):
一個 function 調用或重載的運算符表達式,其返回類型是對 object 的右值引用,例如 std::move(x);
這正是std::decltype<long>()
的含義:它有一個對 object 的右值引用作為其返回類型,因此它返回一個右值。
相反,如果您調用std::decltype<T&>()
並將long
作為T
傳遞,則調用將為std::decltype<long&>()
,在這種情況下,返回類型將為long&
,因此調用將返回一個左值。 請參閱來自同一頁面的以下左值示例的引用
function 調用或重載的運算符表達式,其返回類型為左值引用;
舉一個std::decltype
正在做什么的例子,這些都通過
static_assert(std::is_same_v<decltype(std::declval<int>()), int&&>);
static_assert(std::is_same_v<decltype(std::declval<int&>()), int&>);
這無法編譯
int x;
std::cin >> static_cast<int&&>(x); // XXX
其中// XXX
行是std::declval<std::istream>() >> std::declval<V>()
“模擬”的內容。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.