2017-10-12 25 views
0

我目前正在嘗試自學可變模板。但是,我無法理解通過簡單添加模板的任何內容。如何實現將用戶輸入讀入提供的所有變量的可變參數模板?

目前,我想一個模板,將做到以下幾點:

  1. 採取任何數量的類型
  2. 注意到,要求用戶參數按以下格式輸入它們:

    ŧ值,字符串描述符

  3. 然後逐個遍歷每個變量,在讀取變量之前打印描述符

例如輸出應該是這樣的:

x (int) //this is the descriptor 
//here something is being read into the variable x 
y (int) //this is another descriptor 
//something else is being read into y 
. 
. 
. 

自總是相同的操作,這應該是可能的。然而我最好的嘗試看起來是這樣的

template<typename t,typename... Args> 
void generic_reader(t first,string desc,Args... args) 
{ 
    cout<<desc<<endl; 
    cin>>first; 
    generic_reader(args); 
} 

顯然這並不奏效。但我不能想到另一種做法。再次,我只開始使用可變參數模板。

有人可以告訴我一個解決方案的詳細解釋嗎?

回答

4

下面是使用遞歸的一種方法。

#include <iostream> 

// provide a terminating case 
void generic_read() 
{ 
} 

// provide the general case which picks off the first 2 arguments 
// and forwards the rest to another version of itself. 

template<typename T, typename Printable, typename...Rest> 
void generic_read(T& value ,Printable&& desc,Rest&&...rest) 
{ 
    std::cout << desc << std::endl; 
    std::cin >> value; 
    generic_read(std::forward<Rest>(rest)...); 
} 

// test 
int main() 
{ 
    int x; 
    double y; 

    generic_read(x, "an integer:", y, "a double"); 
} 
2

你基本上存在 - 你只是缺少一個基本情況。另外,您在遞歸調用generic_reader時錯過了...;它應該是generic_reader(args...)

這裏的一些工作的代碼,做你想要做什麼:

#include <string> 
#include <iostream> 

void generic_reader() 
{ 
    std::cout << "no more stuff!" << std::endl; 
} 

template <typename T, typename... Args> 
void generic_reader(T& first, const std::string& desc, Args&... args) 
{ 
    std::cout << desc << std::endl; 
    std::cin >> first; 
    std::cin.ignore(100, '\n'); 
    generic_reader(args...); 
} 


int main() 
{ 
    int x, y, z; 

    generic_reader(x, "x", y, "y", z, "z"); 

    std::cout << "x: " << x << " y: " << y << " z: " << z << std::endl; 

    return 0; 
} 
` 

遍歷代碼:你的做法是正確的,但是當你運行的參數有沒有基本情況。在倒數第二次電話會議上,剩下的參數是(z, "z"),它們可成功替換爲模板。但在此之後,最後還有一個電話號碼爲generic_reader(),沒有任何餘地。您需要提供一個可以接受最終(空)參數列表的候選人。

最後一個注意事項 - 您會注意到我通過引用傳遞了first,所以我可以寫入原始變量。如果你這樣做,確保其餘Args...也通過引用傳遞!否則,遞歸調用將按值傳遞剩餘的參數,並且在第一個調用之後調用將不再引用原始變量。

1

在我看來,您使用的序列號爲std::pairs,其中第一個類型是固定的,std::string,第二個是可變類型。

所以,你可以寫你的功能

template <typename ... Args> 
void generic_reader (std::pair<std::string, Args> & ... ps) 
{ /* do something */} 

,並把它作爲

auto a = std::make_pair<std::string>("a", short(0)); 
auto b = std::make_pair<std::string>("b", 1); 
auto c = std::make_pair<std::string>("c", 2L); 
auto d = std::make_pair<std::string>("d", 3LL); 

generic_reader(a, b, c, d); 

不幸的是,我不知道(前C++ 17)如何在體內使用ps...函數如此,在C++ 11和C++ 17中,我能想到的最好的解決方案是基於遞歸的方案(因爲您的原始版本,在generic_reader(args...);中糾正了遞歸調用)

從C++ 17日開始它的可用的使用可變參數一個新的(更強大)模式(尋找「摺疊式」)和你的函數CA簡寫成

template <typename ... Args> 
void generic_reader (std::pair<std::string, Args> & ... ps) 
{ ((std::cout << ps.first << std::endl, std::cin >> ps.second), ...) ; } 

下面是一個完整的運行的C++ 17例

#include <utility> 
#include <iostream> 

template <typename ... Args> 
void generic_reader (std::pair<std::string, Args> & ... ps) 
{ ((std::cout << ps.first << std::endl, std::cin >> ps.second), ...) ; } 

template <typename ... Args> 
void variadic_printer (Args & ... as) 
{ ((std::cout << as.first << ", " << as.second << std::endl), ...) ; } 

int main() 
{ 
    auto a = std::make_pair<std::string>("a", short(0)); 
    auto b = std::make_pair<std::string>("b", 1); 
    auto c = std::make_pair<std::string>("c", 2L); 
    auto d = std::make_pair<std::string>("d", 3LL); 

    generic_reader(a, b, c, d); 

    variadic_printer(a, b, c, d); 
} 
1

如果你不喜歡使用遞歸你可以隨時使用這個(C++ 14,但也存在C++ 11的index_sequence實現):

#include <utility> 
#include <iostream> 
#include <tuple> 

template <class Tuple, std::size_t... Is> 
void generic_reader_impl(std::index_sequence<Is...>, Tuple&& tuple) { 
    std::size_t dummy[] = { 0ul, 
     (static_cast<void>(std::cout << std::get<2ul*Is + 1ul>(tuple) << std::endl), 
     static_cast<void>(std::cin >> std::get<2ul*Is>(tuple)), 
     Is)... 
    }; 
    static_cast<void>(dummy); 
} 

template <class... Args> 
void generic_reader(Args&&... args) { 
    generic_reader_impl(std::make_index_sequence<sizeof...(Args)/2>{}, std::forward_as_tuple(std::forward<Args>(args)...)); 
} 

int main() { 
    int x; 
    double y; 
    generic_reader(x, "an integer:", y, "a double"); 
    std::cout << x << std::endl; 
    std::cout << y << std::endl; 
} 

Outpu T:

1 
1.2 

[live demo]

相關問題