完美的位域转发解决方法

时间:2013-06-04 20:27:26

标签: c++ templates c++11 bit-fields perfect-forwarding

我正在寻找bit-field in overload resolution for template的解决方法。

我有一个函数,我模仿完美转发其参数:

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);
    ^

3 个答案:

答案 0 :(得分:2)

这是不可能的(至少不是你怎么做的),因为标准这样说(大胆强调我的):

13.3.3.1.4参考绑定[over.ics.ref]

  

4绑定对特定参数的引用的其他限制   不是基于引用的类型和参数的做法   但是,并不影响标准转换序列的形成。   [示例:具有“lvalue reference to int”参数的函数可以   即使相应的参数是int,也是一个可行的候选者   比特网络连接场。隐式转换序列的形成对待   int bit-fi eld as int lvalue并找到与之完全匹配   参数。 如果通过重载分辨率选择该功能,则   尽管如此,由于禁止呼叫,呼叫将会形成不良   将非常量左值引用绑定到位字段(8.5.3)。 - 结束   例子]

这解释了为什么

  • 原始示例无法编译,因为引用无法绑定到位字段
  • 添加一个重载template<typename... Arg> f(Args.. args)给你一个歧义:过载资源以平局结束,并且引用绑定到位域禁止从未发挥作用。

答案 1 :(得分:2)

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,但我会将其修改为用户的例外情况。

答案 2 :(得分:0)

这是我能提出的最佳答案:

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);
}