提问人:G B 提问时间:8/30/2023 最后编辑:G B 更新时间:8/30/2023 访问量:63
专用化可调参数以跳过非参考参数
Specialize variadic template to skip non-reference parameters
问:
我正在为一些客户端-服务器函数调用编写一个包装器,我需要一种方法在实际调用之前或之后设置一些输出参数。示例代码如下:
#include <iostream>
#include <functional>
#include <string>
#include <vector>
void tryp(int a, int b, int &c, std::vector<char> ghost) { c = 7; }
void AssignRefs() {
std::cout << "P2" << std::endl;
}
template <typename T>
void IsolateRef(T &&t) {
t = 99;
}
template<typename T, typename ... A>
void AssignRefs(T &&t, A && ... a) {
IsolateRef(t);
std::cout << "P1" << std::endl;
AssignRefs(a ...);
}
template<typename ... A>
std::function<void(A ...)> wrap(void (*fn)(A ...)) {
return [](A ... a) { AssignRefs(a ...); };
}
int main() {
int z = 6;
int y = 4;
int a = 9;
int b = 77;
tryp(1,4,y,std::vector<char>{'H'});
wrap(tryp)(1,2,z,std::vector<char>{'Z'});
std::cout << "Results here: " << y << " :: " << z << " :: " << a << " :: " << b << std::endl;
}
这当然不会编译。有关详细信息,请参阅在线试用! 链接。如果我删除该行,它会起作用。"t = 99"
我真正需要的是用于或跳过非引用参数的模板专用化。AssignRefs
IsolateRef
现在的问题是,如果我在函数定义中省略 before 类型,所有参数都将失去其引用限定符,并且调用 to 不会执行任何操作。但是每个参数都是通过引用传递给函数的。'&&'
IsolateRef
'&&'
IsolateRef
我想要两个独立的函数,一个用于操作非常量引用类型,另一个用于跳过其余参数。
有没有简单的方法可以在上面的代码中实现它?
多谢。
答:
2赞
YSC
8/30/2023
#1
一个快速的解决方案可能是检查是否可以分配 99:t
#include <type_traits>
// [...]
if constexpr (std::is_assignable_v<T&&, int>) {
IsolateRef(t);
}
然后,您可以改进为不可赋值类型的空操作,以便在不了解其内部结构的情况下调用它:IsolateRef
#include <type_traits>
template<class T>
concept IntAssignable = std::is_assignable_v<T, int>;
template <typename T>
requires (IntAssignable<T&&>)
void IsolateRef(T &&t) {
t = 99;
}
template <typename T>
requires (!IntAssignable<T&&>)
void IsolateRef(T &&)
{}
// ...
int n;
std::vector<int> v;
IsolateRef(n); // assigns
IsolateRef(v); // no-op
评论
0赞
G B
8/30/2023
这是我已经尝试过的东西,但它实际上并没有将 ref 与非 ref 分开。我需要为某些参数分配一个值,但前提是它们被定义为对任何类型的引用,而不仅仅是整数。std::enable_if
0赞
YSC
8/30/2023
我从你的问题中了解到,核心问题不是你的参数的参考性,而是它们被分配的能力。无论是否引用,分配给向量都会失败。这个答案解决了这个问题。如果这不能解决您的问题,请澄清问题。此答案修复了 OP 中给出的代码。99
99
0赞
G B
8/30/2023
我还更新了问题标题以反映这一点。无论如何,谢谢。
0赞
YSC
8/30/2023
你愿意将向量作为参考传递给吗? ?wrap(f)
auto v = std::vector<char>{'V'}; wrap(tryp)(v);
0赞
G B
8/30/2023
是的,这可能会发生,然后另一个模板函数的专用化将处理这种情况并填充向量。
2赞
Weijun Zhou
8/30/2023
#2
一个快速的解决方案刚刚出现在我的脑海中。
#include <iostream>
#include <functional>
#include <string>
#include <vector>
template <typename T>
void IsolateRef(T &&t) {
t = 99;
}
template<typename... Ts>
std::function<void(Ts...)> wrap(void (*fn)(Ts...)){
return [](Ts... args){
([]<typename V>(V&& v){
if constexpr(std::is_reference_v<Ts>){
IsolateRef(std::forward<V>(v));
}
}(args), ...);
};
}
void tryp(int a, int b, int &c, std::vector<char> ghost) { c = 7; }
int main() {
int z = 6;
int y = 4;
int a = 9;
int b = 77;
tryp(1,4,y,std::vector<char>{'H'});
wrap(tryp)(1,2,z,std::vector<char>{'Z'});
std::cout << "Hello, World! " << y << " :: " << z << " :: " << a << " :: " << b << std::endl;
}
我最初写了一个函数特征来提取原始函数的参数类型,包括它们是否是引用。然而,事实证明它并不是真正需要的。
演示:https://godbolt.org/z/n9EdvGxbn
为了完整起见,这是我最初写的函数特性:
template<typename F, int N> struct DumbFunctionTrait{};
template<typename R, typename... Ts, int N>
struct DumbFunctionTrait<R(Ts...), N>{
using type = std::tuple_element_t<N, std::tuple<Ts...>>;
};
此解决方案更通用,不包含特定于 或 的任何内容。但是,我不确定这是 OP 需要的,或者它是否是 XY 问题。这是我能回答上述问题的最好方法。int
99
1赞
Jarod42
8/30/2023
#3
在代码中,可以使用并替换为 2 个重载,一个用于非常量引用,另一个用于常量引用(无操作)std::forward
IsolateRef(T &&t)
template <typename T> void IsolateRef(T &t) { t = 99; }
template <typename T> void IsolateRef(const T &) { /*Empty*/ }
template<typename T, typename ... A>
void AssignRefs(T &&t, A && ... a) {
IsolateRef(std::forward<T>(t));
std::cout << "P1" << std::endl;
AssignRefs(std::forward<A>(a) ...);
}
template<typename ... A>
std::function<void(A ...)> wrap(void (*fn)(A ...)) {
return [](A ... a) { AssignRefs(std::forward<A>(a) ...); };
}
评论
1赞
G B
8/30/2023
是的,这绝对比其他所有解决方案都容易。这只是我缺少的一小块。非常感谢。
评论