迭代可变参数是最简单的部分:您标记了 C++17,以便可以使用 JeJo 建议的模板折叠或其他方式(递归、未使用数组的初始化)。
更复杂的是,所有的参数都是完全相同的类型。
显然你可以使用 SFINAE 来强制推导的类型是相同的类型,但是如果你传递不同类型的参数,例如
foo(1l, 2l, 3l, 4); // long, long, long, int
当一个参数可以转换为其他参数的类型时,代码不会编译。
如果您接受传递附加函数并且您的函数是模板结构的方法,则可以从 using 开始,从一对类型/索引中选择类型
template <typename T, std::size_t>
using get_type = T;
模板结构可以这样写
template <typename...>
struct bar;
template <typename T, std::size_t ... Is>
struct bar<T, std::index_sequence<Is...>>
{
void operator() (std::string const & str, get_type<T, Is> const & ... ts)
{ ((std::cout << ts << ' '), ..., (std::cout << '\n')); }
};
注意operator() 中str 后面的参数都是T 类型,其中T 是结构的第一个模板参数。
附加功能是
template <typename T, typename ... Ts>
void foo (std::string const & str, Ts const & ... ts)
{ bar<T, std::index_sequence_for<Ts...>>{}(str, ts...); }
您可以拨打foo()如下
foo<int>("string", 1, 2, 3, 4l);
观察到 long 值 (4l) 被接受,因为它被转换为 int。
如果您愿意,也可以直接拨打bar::operator()
bar<int, std::make_index_sequence<4u>>{}("string", 10, 20, 30, 40);
但你必须明确第二个模板参数,所以会有一些冗余。
以下是完整的编译示例
#include <string>
#include <utility>
#include <iostream>
template <typename T, std::size_t>
using get_type = T;
template <typename...>
struct bar;
template <typename T, std::size_t ... Is>
struct bar<T, std::index_sequence<Is...>>
{
void operator() (std::string const & str, get_type<T, Is> const & ... ts)
{ ((std::cout << ts << ' '), ..., (std::cout << '\n')); }
};
template <typename T, typename ... Ts>
void foo (std::string const & str, Ts const & ... ts)
{ bar<T, std::index_sequence_for<Ts...>>{}(str, ts...); }
int main ()
{
foo<int>("string", 1, 2, 3, 4l); // a long value is converted to int
bar<int, std::make_index_sequence<4u>>{}("string", 10, 20, 30, 40);
}