[英]How do I implement a variadic template that reads user input into all variables supplied?
我目前正在尝试自学可变参数模板。 但是,我无法理解除简单添加模板之外的任何内容。
目前,我需要一个可以执行以下操作的模板:
采用需要用户以以下格式输入的参数:
T值,字符串描述符
例如,输出应如下所示:
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.