6

template のオーバーロード解決でビットフィールドの回避策を探しています。

引数を完全に転送するためにテンプレート化した関数があります。

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()ビットフィールドを値で受け取るが、一般的なケースで他の引数を参照で受け取るようにオーバーロードする方法はありますか?

これまでのところ、私はできませんでした。たとえば、引数を値で受け取るオーバーロードを追加すると…</p>

main.cpp:27:5: エラー: 'f' の呼び出しがあいまいです
    f(b.foo);
    ^
4

3 に答える 3

2

標準がそう言っているので、それはできません(少なくともあなたが試した方法ではありません)(太字の強調鉱山):

13.3.3.1.4 参照バインディング [over.ics.ref]

4 ただし、参照と引数の型に基づかない特定の引数への参照のバインドに関するその他の制限は、標準の変換シーケンスの形成には影響しません。[例: 「int への左辺値参照」パラメータを持つ関数は、対応する引数が int ビットフィールドであっても実行可能な候補になる可能性があります。暗黙的な変換シーケンスの形成では、int ビットフィールドが int 左辺値として扱われ、パラメーターとの正確な一致が検出されます。関数がオーバーロードの解決によって選択された場合でも、ビット フィールド(8.5.3)への非 const 左辺値参照のバインドが禁止されているため、呼び出しは不適切な形式になります。— 終了例 ]

これは理由を説明します

  • 参照がビットフィールドにバインドできないため、元の例はコンパイルに失敗します
  • オーバーロードを追加するtemplate<typename... Arg> f(Args.. args)と、あいまいさが生じました。オーバーロードの解決は引き分けで終了し、ビットフィールドへの参照バインディングの禁止は決して機能しませんでした。
于 2013-06-04T20:49:11.303 に答える
2

これは私が思いつくことができる最良の答えです:

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);
}
于 2016-10-24T23:51:58.883 に答える
2

http://coliru.stacked-crooked.com/view?id=b694c6cc3a52e0c14bedd6a26790d99d-e54ee7a04e4b807da0930236d4cc94dc

下手でも出来ます。これをしないことをお勧めします。基本的に、重要な部分は、ビットフィールドへのポインターまたは参照を持つことができないため、代わりにビットフィールドを設定するラムダを使用することです。

私は次の男と同じくらいマクロが嫌いですが、呼び出し元で呼び出し元にラムダを入れる必要を避けるために私が考えることができる唯一の方法です。

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値が aboolではなく , であると想定していることに気付きunsigned intましたが、ユーザーの演習としてそれを修正しておきます。

于 2013-06-04T21:21:00.887 に答える