位域的完美转发解决方案
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:错误:非const引用不能绑定到位域'foo'f (b.foo);^ ~ ~ ~ ~ 之前是否有一种方法可以重载
f()
,使其按值接受位域,但在普通情况下仍然通过引用接受其他参数?到目前为止我还没能。例如,如果我添加一个重载,通过value…接受参数
main.cpp:27:5: error:调用'f'是不明确的f (b.foo);^
这是不可能的(至少不是你怎么尝试的),因为标准是这么说的(粗体强调我的):
13.3.3.1.4引用绑定(over.ics.ref)
4将引用绑定到特定实参的其他限制它们不是基于引用的类型,而是基于实参的类型但是,不影响标准转换序列的形成。[示例:带"左值引用int"形参的函数可以即使对应的实参是int型,也要成为可行的候选者位域。隐式转换序列的形成处理Int位域作为Int左值,并找到与的精确匹配参数。如果函数是通过重载解析选择的,则尽管如此,由于禁止,呼叫仍将是病态的将非const左值引用绑定到位域(8.5.3)。- - -结束例]
这解释了为什么
- 原始示例无法编译,因为引用无法绑定到位域
- 添加一个重载
template<typename... Arg> f(Args.. args)
给你带来了歧义:重载解析以平局结束,并且引用绑定到位域的禁止从未发挥作用。
这是我能想到的最好的答案:
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));
}
编辑:有一个更简单的解决方案,消除了对'便秘'模板的需要:
void bar()
{
bits b{1};
f(b.foo + 0);
}
http://coliru.stacked-crooked.com/view?id=b694c6cc3a52e0c14bedd6a26790d99d-e54ee7a04e4b807da0930236d4cc94dc
如果做得不好,这是可以做到的。我建议不要这样做。基本上,关键的部分是,因为你不能有一个指向位域的指针或引用,你可以使用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
,但我将把它作为用户的练习来修复。
- 运行同一解决方案的另一个项目的项目
- Project Euler问题4的错误解决方案
- 计算每个节点的树高,帮助我解释这个代码解决方案
- C++:Application.cpp中抛出了未解析的外部符号(解决方案在问题的末尾,供未来的读者参考)
- visual c++,如何获取解决方案目录中的代码
- 有没有办法在远程设备上打开和编辑visual Studio 2017解决方案
- C++Matching Brackets 2解决方案不起作用
- 在 ubuntu3 上C++ goto 定义有什么解决方案吗16.04?
- 在 leetcode 上提交解决方案时出现堆栈缓冲区溢出错误
- 我的固定时间步长与增量时间和插值的解决方案是错误的吗?
- 无法在问题解决方案中执行输出逻辑
- 最大的回文产品 - 程序未运行,编写解决方案但无法理解问题
- 从预序遍历构造 bst 的 c++ 和 python 解决方案之间的区别
- 在一个解决方案中针对第三方静态库 (Creo) 的不同版本(版本)进行构建
- 如何巧妙地编写两个函数——一个用于检查是否存在解决方案,另一个用于获取所有解决方案
- 使用 Git 处理 C++ Visual Studio 2019 解决方案的外部依赖项源代码管理的最佳方法是什么?
- N-queen问题:无法弄清楚为什么我的解决方案不起作用
- 从排序数组中删除重复项,具有不同代码方式的相同解决方案具有不同的输出
- 使用XOR查找O(n)-解决方案中的两个字符串是否为变位符
- 位域的完美转发解决方案