簡體   English   中英

元組和可變參數模板,這是如何工作的?

[英]Tuple and variadic templates, how does this work?

我見過人們寫(在堆棧溢出本身,詢問一些甚至高級概念)的東西:

template<typename... args>
std::tuple<args...> parse(istream stream) 
{
    return std::make_tuple(args(stream)...);
}

並用它作為

auto tup = parse<int, float, char>(stream);

上面的代碼如何通過解析流來構造元組? 是否有關於如何將數據放入流中的具體要求?

為此,必須有一個從std::istream到指定為模板參數的所有類型的隱式轉換。

struct A {
    A(std::istream&) {} // A can be constructed from 'std::istream'.
};

struct B {
    B(std::istream&) {} // B can be constructed from 'std::istream'.
};

int main() {
    std::istringstream stream{"t1 t2"};
    auto tup = parse<A, B>(stream);
}

它的工作原理是擴展可變參數類型列表,並使用提供的std::istream作為參數構造每個類型。 然后將其留給每種類型的構造函數以從流中讀取。

另請注意,未指定構造函數的求值順序,因此您不能指望可變參數列表中的第一個類型將首先從流中讀取。

代碼本身不適用於intfloatchar內置類型,因為沒有從std::istream到任何這些類型的轉換。

它的效果很差。 它依賴於具有帶std::istream的構造函數的目標類型。

由於許多類型沒有這個,並且你不能將它添加到像int這樣的東西,這是一個糟糕的計划。

而是這樣做:

template<class T>
auto read_from_stream( std::istream& stream, T* unused_type_tag )
-> typename std::decay<decltype( T{stream} )>::type
{
  return {stream};
}
template<class T>
auto read_from_stream( std::istream& stream, T* unused_type_tag, ... )
-> typename std::decay<decltype( T(stream) )>::type
{
  return T(stream);
}

template<typename... args>
std::tuple<args...> parse(std::istream& stream)  {
  return std::tuple<args...>{
    read_from_stream(stream, (args*)nullptr)...
  };
}

現在我們不是直接構造參數,而是調用read_from_stream

read_from_stream上面有兩個重載。 第一個嘗試直接和隱式地從istream構造我們的對象。 第二個顯式從istream構造我們的對象,然后使用RVO返回它。 ...確保第二個僅在第一個失敗時使用。

無論如何,這開辟了一個定制點。 在類型X的命名空間中,我們可以編寫一個read_from_stream( std::istream&, X* )函數,它將自動被調用,而不是上面的默認實現。 我們還可以編寫read_from_stream( std::istream&, int* ) (等),它可以知道如何解析istream整數。

這種自定義點也可以使用traits類來完成,但是使用重載執行它有許多優點:您可以將自定義注入到類型旁邊,而不必打開完全不同的命名空間。 自定義操作也更短(沒有類包裝噪音)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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