[英]C++ template with variadic argument specialization for number of arguments
[英]C++ variadic template empty argument specialization
为空参数可变参数模板编写专业化的正确方法是什么。 以下面的代码为例:
#include <iostream>
#include <memory>
#include <tuple>
#include <functional>
#include <cassert>
using namespace std;
struct message {
int type;
};
struct X: message {
int payload;
X(): message{1} {
}
};
struct Y: message {
int payload;
Y(): message{2} {
}
};
struct Z: message {
int payload;
Z(): message{3} {
}
};
template<typename T>
constexpr int message_type = -1;
template<>
constexpr int message_type<X> = 1;
template<>
constexpr int message_type<Y> = 2;
template<>
constexpr int message_type<Z> = 3;
struct M {
int payload;
M(int payload): payload{ payload } {
}
};
template<typename P, typename T1, typename... Ts>
tuple<int, unique_ptr<M>> helper(unique_ptr<message> &msg, function<int(unique_ptr<T1>&)> fn1, function<int(unique_ptr<Ts>&)>... fn) {
if (msg->type == message_type<T1>) {
unique_ptr<T1> m(static_cast<T1*>(msg.release()));
auto result = fn1(m);
return {result, make_unique<M>(m->payload)};
} else {
return helper<void, Ts...>(msg, fn...);
}
}
template<typename P>
tuple<int, unique_ptr<M>> helper(unique_ptr<message> &msg) {
assert(false);
return {0, unique_ptr<M>()};
}
template<typename... Ts>
tuple<int, unique_ptr<M>> dispatch_msg(unique_ptr<message> &msg, function<int(unique_ptr<Ts>&)> ...fn) {
return helper<void, Ts...>(msg, fn...);
}
int main() {
auto *real_message = new Z;
real_message->payload = 101;
unique_ptr<message> msg(real_message);
auto [result, m] = dispatch_msg<X, Y, Z>(msg, [](auto &x) {
return x->payload + 1;
}, [](auto &y) {
return y->payload + 2;
}, [](auto &z) {
return z->payload + 3;
});
cout << result << '\n' << m->payload << endl;
return 0;
}
helper
function 采用可变参数模板 arguments。 如果它检查了所有给定类型 arguments 并失败。 例如运行到空的 arguments。 我想断言并停止该过程。 当前代码有效,但我想知道是否有任何直接的方法来编写专业化。
我将核心要求简化为以下代码:
template<typename T, typename... Ts>
void func(int val, T arg, Ts... args) {
if (condition_hold<T>(val)) {
return;
} else {
return func<Ts...>(val, args...);
}
}
template<>
void func(int val) {
assert(false);
}
int main() {
func<int, double, float>(100);
return 0;
}
基本上,该func
正在检查每个给定类型是否符合输入val
的条件。 如果所有检查都失败了,我想做一些事情,比如这里的assert
。 所以我写了一个专业化的空参数,但这无法编译。
在 C++17 中,大多数情况下您不需要将参数包拆分为头部和尾部。 多亏了折叠表达式,对包的许多操作变得更加容易。
// Some generic predicate.
template <typename T>
bool condition_hold(T) {
return true;
}
// Make this whatever you want.
void do_something_with(int);
template<typename... Ts>
auto func(int val, Ts... args) {
// Fold expression checks whether the condition is true for all
// elements of the parameter pack.
// Will be true if the parameter pack is empty.
if ((condition_hold(args) && ...))
do_something_with(val);
}
int main() {
// Ts type parameters are deduced to <float, float>.
func(100, 1.f, 2.f);
return 0;
}
要检查包装是否为空并专门处理这种情况,您可以执行以下操作:
template<typename... Ts>
auto func(int val, Ts... args) {
if constexpr (sizeof...(Ts) == 0) {
// handle empty pack
}
else {
// handle non-empty pack
}
}
由于func<>
需要至少一个参数,因此您的专业化无法奏效。 专业如
template<typename T>
void func<T>(int val);
也不是有效的,因为它是只允许类的部分专业化。 但是,如果基本模板只需要一个包,我们可以完全专门化它:
template<typename... Ts>
void func(int val, Ts... args);
template<>
void func<>(int val);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.