在可变模板函数中为每个模板类型调用 void 函数?
Call void function for each template type in a variadic templated function?
我的目标是编写一个简单的通用函数来为任意 C++ 类型注册转换器。为简单起见,我只打印 C++ 类型名称。我希望能够为任何类型调用我的通用 print_type_name
函数,包括一次包含多种类型(可变参数):
template <typename T>
void print_type_name(void)
{
std::cout << typeid(T).name() << std::endl;
}
这适用于这样的事情:
print_type_name<int>();
print_type_name<std::string>();
print_type_name<std::vector<std::complex<float> > >();
但是,我需要能够为可变参数模板中的每种类型调用此函数,例如(展开后):
print_type_name<int, std::string, std::vector<std::complex<float> > >();
这是我想出的,但它相当笨拙:
template <typename ...TS>
void noop(TS... ts) { }
template <typename T>
int real_print_type_name(void) {
std::cout << typeid(T).name() << std::endl;
return 0;
}
template <typename ...TS>
void print_type_name(void) {
noop(real_print_type_name<TS>()...);
}
允许以下情况:
template <typename ...TS>
void other_function(void) {
print_type_name<TS...>();
}
注意无用的 noop
函数和 int
return 类型
real_print_type_name
,我必须添加这两个才能扩展
参数包。有更简洁的方法吗?
我认为你可以这样做:
void print_type_name()
{
std::cout<<"\n";
}
template <typename T>
void print_type_name(const T& t)
{
std::cout<<t<<" : of type "<<typeid(t).name()<<"\n";
}
template <typename T1, typename... Ts>
void print_type_name(const T1& t1, const Ts&... ts)
{
// Head
std::cout<<t1<<" : of type "<<typeid(t1).name()<<", ";
// Tail
print_type_name(ts...);
}
不知道清楚了没有。
template <typename ...TS>
void print_type_name() {
using expander = int[];
(void) expander{ 0, (std::cout << typeid(TS).name() << '\n', 0)... };
}
或者,C++17 风格:
template <typename ...TS>
void print_type_name(void) {
(std::cout << ... << (typeid(TS).name() + "\n"s));
}
Demo.
这是一个辅助函数。它使用随机黑魔法,但它的名字很清楚:
void do_in_order() {}
template<class...Fs>
void do_in_order( Fs&&...fs ) {
using discard=int[];
(void)discard{0, (void(
std::forward<Fs>(fs)()
),0)... };
}
或者在 C++17 中:
template<class...Fs>
void do_in_order( Fs&&...fs ) {
(void(std::forward<Fs>(fs)())...);
}
(更好)。
这隐藏了任何丑陋。它需要一组 void()
个可调用对象和调用
他们从左到右 -- 它按顺序执行任务,就像罐头上写的那样。
然后print_type_names
变成:
template<class...Ts>
void print_type_names() {
do_in_order( print_type_name<Ts>... );
}
或
template<class...Ts>
void print_type_names() {
do_in_order( [&]{
std::cout << typeid(Ts).name() << std::endl;
}... );
}
如果您不想使用单个 print_type_name
函数并希望将其内联。
请注意,一些不合格的编译器抱怨在 ...
中展开整个 lambda。
我的目标是编写一个简单的通用函数来为任意 C++ 类型注册转换器。为简单起见,我只打印 C++ 类型名称。我希望能够为任何类型调用我的通用 print_type_name
函数,包括一次包含多种类型(可变参数):
template <typename T>
void print_type_name(void)
{
std::cout << typeid(T).name() << std::endl;
}
这适用于这样的事情:
print_type_name<int>();
print_type_name<std::string>();
print_type_name<std::vector<std::complex<float> > >();
但是,我需要能够为可变参数模板中的每种类型调用此函数,例如(展开后):
print_type_name<int, std::string, std::vector<std::complex<float> > >();
这是我想出的,但它相当笨拙:
template <typename ...TS>
void noop(TS... ts) { }
template <typename T>
int real_print_type_name(void) {
std::cout << typeid(T).name() << std::endl;
return 0;
}
template <typename ...TS>
void print_type_name(void) {
noop(real_print_type_name<TS>()...);
}
允许以下情况:
template <typename ...TS>
void other_function(void) {
print_type_name<TS...>();
}
注意无用的 noop
函数和 int
return 类型
real_print_type_name
,我必须添加这两个才能扩展
参数包。有更简洁的方法吗?
我认为你可以这样做:
void print_type_name()
{
std::cout<<"\n";
}
template <typename T>
void print_type_name(const T& t)
{
std::cout<<t<<" : of type "<<typeid(t).name()<<"\n";
}
template <typename T1, typename... Ts>
void print_type_name(const T1& t1, const Ts&... ts)
{
// Head
std::cout<<t1<<" : of type "<<typeid(t1).name()<<", ";
// Tail
print_type_name(ts...);
}
不知道清楚了没有。
template <typename ...TS>
void print_type_name() {
using expander = int[];
(void) expander{ 0, (std::cout << typeid(TS).name() << '\n', 0)... };
}
或者,C++17 风格:
template <typename ...TS>
void print_type_name(void) {
(std::cout << ... << (typeid(TS).name() + "\n"s));
}
Demo.
这是一个辅助函数。它使用随机黑魔法,但它的名字很清楚:
void do_in_order() {}
template<class...Fs>
void do_in_order( Fs&&...fs ) {
using discard=int[];
(void)discard{0, (void(
std::forward<Fs>(fs)()
),0)... };
}
或者在 C++17 中:
template<class...Fs>
void do_in_order( Fs&&...fs ) {
(void(std::forward<Fs>(fs)())...);
}
(更好)。
这隐藏了任何丑陋。它需要一组 void()
个可调用对象和调用
他们从左到右 -- 它按顺序执行任务,就像罐头上写的那样。
然后print_type_names
变成:
template<class...Ts>
void print_type_names() {
do_in_order( print_type_name<Ts>... );
}
或
template<class...Ts>
void print_type_names() {
do_in_order( [&]{
std::cout << typeid(Ts).name() << std::endl;
}... );
}
如果您不想使用单个 print_type_name
函数并希望将其内联。
请注意,一些不合格的编译器抱怨在 ...
中展开整个 lambda。