簡體   English   中英

如何實現可變參數模板,將用戶輸入讀入提供的所有變量中?

[英]How do I implement a variadic template that reads user input into all variables supplied?

我目前正在嘗試自學可變參數模板。 但是,我無法理解除簡單添加模板之外的任何內容。

目前,我需要一個可以執行以下操作的模板:

  1. 采取任何數量的類型
  2. 采用需要用戶以以下格式輸入的參數:

    T值,字符串描述符

  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);
}

顯然,這不起作用。 但是我想不出另一種方法。 同樣,我只是開始使用可變參數模板。

有人可以向我顯示詳細說明的解決方案嗎?

這是使用遞歸的一種方法。

#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");
}

您基本上就在那兒–您只是缺少一個基本案例。 此外,您在對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...也通過引用傳遞! 否則,遞歸調用將按值傳遞其余的args,並且第一個之后的調用將不再引用原始變量。

在我看來,您使用的是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開始,它提供了一種新的(且功能更強大)的可變參數使用模式(查找“折疊表達式”),並且您的函數可以簡單地編寫為

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);
 }

如果您不想使用遞歸,則可以始終使用它(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;
}

輸出:

1
1.2

[現場演示]

暫無
暫無

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

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