2013-06-04 65 views
2

我正在尋找解決方法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); 
    ^
+2

有辦法,但我認爲_best_選項是不能傳遞位域的。 –

+0

@MooingDuck謹慎添加答案以顯示一些變通方法?直接的做法失敗 – TemplateRex

+0

@MooingDuck花式在這裏看到你:)。我開始走這條路,就像在通話時加入演員一樣簡單。不是很棒,但也不錯。 – s4y

回答

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

它不能這樣做(至少不是你如何嘗試過),因爲標準是這樣說的(粗體重點煤礦):

13.3.3.1.4參考結合[over.ics.ref]

4上的參照結合到沒有基於所述類型的參考和所述參數的一個特定參數 其他限制做 不是FF ECT該然而,形成標準轉換序列。 [例子:即使相應的參數是一個int 位域,具有「左值引用int」參數的函數 也是可行的候選值。隱式轉換序列的形成將int位域當作int左值對待,並發現與參數 完全匹配。 如果該功能是通過重載分辨率選擇的,則 調用仍然是不合格的,因爲禁止 綁定對位字段(8.5.3)的非常量左值引用。 - 結束 示例]

這就解釋了爲什麼

  • 最初的例子無法編譯,因爲引用不能綁定到一個位字段
  • 添加過載template<typename... Arg> f(Args.. args)給你的不確定性:超載資源以平局結束,參考綁定到位域禁止從未發揮作用。
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)); 
} 

編輯:這裏有一個簡單的解決方案,消除了「患便祕」模板需要:

void bar() 
{ 
bits b{1}; 
f(b.foo + 0); 
}