簡體   English   中英

鍵入 trait 以檢查給定類型是否存在 istream 運算符>>

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM