位域的完美转发解决方案

Perfect forwarding workaround for bit-fields

本文关键字:解决方案 转发 完美 位域      更新时间:2023-10-16

我正在寻找模板重载解析中位域的解决方案。

我模板化了一个函数来完美地转发它的参数:

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,但我将把它作为用户的练习来修复。

相关文章: