在构造函数的成员初始化程序列表中使用带有初始化程序的初始化程序列表时编译错误,以初始化匿名联合类型

时间:2019-03-11 05:11:15

标签: c++

在c ++中,我遇到了一种情况,当我在类构造函数的成员初始化器列表中使用带有初始化符的初始化器列表时,初始化匿名联合成员变量失败。

下面的代码片段可能会让事情变得更清楚:

class MyClass {
public:
  MyClass() : my_union({.outer_field = 123}) {}
  union {
    struct {
      int a: 16;
      int b: 16;
    } inner_field;
    int outer_field;
  } my_union;
};

编译器出现以下错误:

test.cpp: In constructor ‘MyClass::MyClass()’:
test.cpp:6:44: error: no matching function for call to ‘MyClass::<anonymous union>::._6(<brace-enclosed initializer list>)’
   MyClass() : my_union({.outer_field = 123}) {}
                                            ^
test.cpp:7:9: note: candidate: MyClass::<anonymous union>::<constructor>()
   union {
         ^
test.cpp:7:9: note:   candidate expects 0 arguments, 1 provided
test.cpp:7:9: note: candidate: constexpr MyClass::<anonymous union>::<constructor>(const MyClass::<anonymous union>&)
test.cpp:7:9: note:   no known conversion for argument 1 from ‘<brace-enclosed initializer list>’ to ‘const MyClass::<anonymous union>&’
test.cpp:7:9: note: candidate: constexpr MyClass::<anonymous union>::<constructor>(MyClass::<anonymous union>&&)
test.cpp:7:9: note:   no known conversion for argument 1 from ‘<brace-enclosed initializer list>’ to ‘MyClass::<anonymous union>&&’

但是,以下代码可以毫无问题地编译;

union myunion {
  struct {
    int a: 16;
    int b: 16;
  } inner_field;
  int outer_field;
} my_union;
myunion m = {.outer_field = 123};

我可以通过调用union的隐式构造函数来解决该问题(如错误消息所示),

class MyClass {
public:
  MyClass() : my_union({123}) {}
  union {
    struct {
      int a: 16;
      int b: 16;
    } inner_field;
    int outer_field;
  } my_union;
};

但是为什么带有指定符的初始值设定列表在成员初始值设定列表中不起作用?

用于编译的g ++版本为5.4.0。

g++ (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

1 个答案:

答案 0 :(得分:0)

从技术上讲,您给出的编译示例不是有效的c ++,而是使用GCC扩展名允许C99指定的初始化器。有关案件:

 public class English extends AppCompatActivity   {
    ViewHolder apt;
    RecyclerView mRecyclerView;
    FirebaseDatabase mFirebaseDatabase;
    DatabaseReference mRef;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_english);


        mRecyclerView = findViewById(R.id.recyclerView);
        mRecyclerView.setHasFixedSize(true);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        mFirebaseDatabase = FirebaseDatabase.getInstance();
        mRef = mFirebaseDatabase.getReference("English");


    }

    private void firebaseSearch(String searchText){
        Query firebaseSearchQuery=mRef.orderByChild("artist").startAt(searchText).endAt(searchText + "\uf8ff");

        FirebaseRecyclerAdapter<englishacti, ViewHolder> firebaseRecyclerAdapter=new FirebaseRecyclerAdapter<englishacti, ViewHolder>(englishacti.class,R.layout.row,ViewHolder.class,firebaseSearchQuery) {
            @Override
            protected void populateViewHolder(ViewHolder holder, englishacti model, int position) {
                holder.setDetails(getApplicationContext(),model.getAlbum(),model.getDescription(),model.getImage(),model.getArtist());
            }
        };
        mRecyclerView.setAdapter(firebaseRecyclerAdapter);
    }

    @Override
    protected void onStart() {
        super.onStart();
        FirebaseRecyclerAdapter<englishacti,ViewHolder> firebaseRecyclerAdapter;
        firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<englishacti, ViewHolder>(englishacti.class,R.layout.row,ViewHolder.class,mRef) {
            @Override

            protected void populateViewHolder(ViewHolder viewHolder, englishacti model, int position) {
                viewHolder.setDetails(getApplicationContext(), model.getAlbum(), model.getDescription(), model.getImage(), model.getArtist());



            }
        };
        mRecyclerView.setAdapter(firebaseRecyclerAdapter);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu,menu);
        MenuItem item = menu.findItem(R.id.action_search);
        SearchView searchView = (SearchView) MenuItemCompat.getActionView(item);
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                firebaseSearch(query);
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                firebaseSearch(newText);
                return false;
            }
        });
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id=item.getItemId();
        if (id==R.id.action_settings){
            return true;
        }
        return super.onOptionsItemSelected(item);
    }




}

但是,这不是使用初始化列表,而是统一初始化。要在代码中获得与未编译时相同的结果,只需删除外部括号即可:

myunion m = {.outer_field = 123};

这不是尝试将初始化程序列表传递给联合的构造函数,而是执行统一的初始化。请记住,它仍在使用GCC扩展,如果将-pedantic传递给编译器,则会生成警告。

编辑: 另外,作为警告,使用统一初始化时,联合会始终初始化第一个成员。结构将零初始化任何缺少的值。因此,您的第一个编译器示例将编译:

class MyClass {
public:
  MyClass() : my_union{.outer_field = 123} {}
  union {
    struct {
      int a: 16;
      int b: 16;
    } inner_field;
    int outer_field;
  } my_union;
};

这实际上将inner_field设置为联合中的活动字段,则a将为123,b将为0。Here is an example。有关初始化并集的更多详细信息,请参见here