[英]Perfect forwarding workaround for bit-fields
我正在寻找模板重载分辨率的位字段的解决方法。
我有一个函数,我模仿完美转发其参数:
template <typename... Args> void f(Args &&...args) { }
如果我尝试将其与位字段参数一起使用,如下所示:
struct bits { unsigned int foo:1; };
bits b{1};
f(b.foo);
......它无法编译:
main.cpp:26:7: error: non-const reference cannot bind to bit-field 'foo' f(b.foo); ^~~~~
有没有办法重载f()
,使得它按值获取位字段,但在常见情况下仍然通过引用获取其他参数?
到目前为止,我还没有。 例如,如果我添加一个按值获取参数的重载...
main.cpp:27:5: error: call to 'f' is ambiguous f(b.foo); ^
它无法完成(至少不是你如何尝试)因为标准如此(大胆强调我的):
13.3.3.1.4引用绑定[over.ics.ref]
4然而,绑定对特定参数的引用的其他限制不是基于引用的类型和参数,也不会影响标准转换序列的形成。 [示例:具有“左值引用到int”参数的函数可以是可行的候选者,即使相应的参数是int位字段也是如此。 隐式转换序列的形成将int比特字段视为整数值,并与参数完全匹配。 如果通过重载决策选择该函数,则由于禁止将非常量左值引用绑定到位字段 (8.5.3) ,因此调用将是格式错误的。 - 结束例子]
这解释了原因
template<typename... Arg> f(Args.. args)
给你的含糊不清:过载资源以平局结束,并且引用绑定到位域禁止从未发挥作用。 如果不好的话,可以做到。 我建议不要这样做。 基本上,关键部分是因为你没有指针或对位域的引用,所以你改为使用lambda为你设置位域。
我不像下一个人那样不喜欢宏,但这是我想到的唯一方法,以避免要求呼叫者在呼叫站点放入lambda。
template<class assigner_type>
struct bitfieldref_type {
bitfieldref_type(bool value, assigner_type&& assign) :value(value), assign(std::move(assign)) {}
operator bool() const {return value;}
bitfieldref_type& operator=(bool v) {assign(v); value=v; return *this;}
private:
bool value;
assigner_type assign;
};
template<class assigner_type>
bitfieldref_type<assigner_type> make_bitfieldref(bool value, assigner_type&& assign)
{return {value, std::move(assign)};}
//macro is optional
#define bitfieldref(X) make_bitfieldref(X, [&](bool v)->void{X=v;})
用法:
template <class T, typename... Args> void proof_it_works(T&& first)
{first = 0;}
template <class T, typename... Args> void proof_it_works(T&& first, Args &&...args) {
first = 0;
proof_it_works(std::forward<Args>(args)...);
}
template <typename... Args> void f(Args &&...args) {proof_it_works(std::forward<Args>(args)...);}
int main() {
struct bits { unsigned int foo:1; };
bits b{1};
int a = -1;
float c = 3.14;
f(a, bitfieldref(b.foo), c);
std::cout << a << b.foo << c;
return 0;
}
我只是注意到我的bitfieldref_type
假设值是一个bool
,而不是unsigned int
,但是我将把它固定为用户的excersize。
这是我能想到的最佳答案:
template <typename... Args> void f(Args &&...args) { }
struct bits { unsigned int foo:1; };
template <typename T> const T constipate(T v)
{ return(static_cast<const T>(v)); }
void bar()
{
bits b{1};
f(constipate(b.foo));
}
编辑:有一个更简单的解决方案,消除了对'constipate'模板的需求:
void bar()
{
bits b{1};
f(b.foo + 0);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.