エラーになるのは何故?(デフォルトコンストラクタの合成)
コード(1)
// main.cpp struct A { A (int a) { } }; int main() { A a; }
コンパイルエラー
$ g++ main.cpp main.cpp: In function 'int main()': main.cpp:12: error: no matching function for call to 'A::A()' main.cpp:5: note: candidates are: A::A(int) main.cpp:4: note: A::A(const A&)
コード(2)
// main.cpp struct A { A (int a) { } }; struct B { A a; }; int main() { B b; }
コンパイルエラー
$ g++ main.cpp main.cpp: In constructor 'B::B()': main.cpp:11: error: no matching function for call to 'A::A()' main.cpp:5: note: candidates are: A::A(int) main.cpp:4: note: A::A(const A&) main.cpp: In function 'int main()': main.cpp:17: note: synthesized method 'B::B()' first required here
コード(3)
// main.cpp struct A { A (int a) { } }; struct B : A { }; int main() { B b; }
コンパイルエラー
$ g++ main.cpp main.cpp: In constructor 'B::B()': main.cpp:12: error: no matching function for call to 'A::A()' main.cpp:5: note: candidates are: A::A(int) main.cpp:4: note: A::A(const A&) main.cpp: In function 'int main()': main.cpp:17: note: synthesized method 'B::B()' first required here
答え
デフォルトコンストラクタがないから
解説
クラスにコンストラクタがない場合は、デフォルトコンストラクタがコンパイラによって合成される。しかし、以下のような場合にデフォルトコンストラクタは合成されない。
- 明示的に定義されたデフォルトコンストラクタ以外のコンストラクタが 1 つ以上あるクラス ... コード(1)
- デフォルトコンストラクタを持たないクラス型のメンバ変数を持つクラス ... コード(2)
- デフォルトコンストラクタを持たないクラス型を継承するクラス ... コード(3)
デフォルトコンストラクタを持たないメリットはあまりない。そのため、空という意味を持つ特殊なオブジェクトを生成するためのデフォルトコンストラクタを別途宣言したりすることが多い。
デフォルトコンストラクタがないとできないことは、関連エントリを参照。
エラーになるのは何故?(デフォルトコンストラクタの呼び出し)
コード(1)
// main.cpp struct A { A(int a) { } }; int main() { A a; }
コンパイルエラー
$ g++ main.cpp main.cpp: In function 'int main()': main.cpp:12: error: no matching function for call to 'A::A()' main.cpp:5: note: candidates are: A::A(int) main.cpp:4: note: A::A(const A&)
コード(2)
// main.cpp struct A { A(int a) { } }; int main() { A* a = new A[10]; delete[] a; }
コンパイルエラー
$ g++ main.cpp main.cpp: In function 'int main()': main.cpp:12: error: no matching function for call to 'A::A()' main.cpp:5: note: candidates are: A::A(int) main.cpp:4: note: A::A(const A&)
コード(3)
// main.cpp struct A { A(int a) { } }; int main() { A a[10]; }
コンパイルエラー
$ g++ main.cpp main.cpp: In function 'int main()': main.cpp:12: error: no matching function for call to 'A::A()' main.cpp:5: note: candidates are: A::A(int) main.cpp:4: note: A::A(const A&)
コード(4)
// main.cpp #include <vector> struct A { A(int a) { } }; int main() { std::vector<A> a(10); }
コンパイルエラー
$ g++ main.cpp main.cpp: In constructor 'std::vector<_Tp, _Alloc>::vector(size_t, const _Tp&, const _Alloc&) [with _Tp = A, _Alloc = std::allocator<A>]': main.cpp:14: error: no matching function for call to 'A::A()' main.cpp:7: note: candidates are: A::A(int) main.cpp:6: note: A::A(const A&)
答え
クラス A がデフォルトコンストラクタを持たないから
非 const 参照の初期化子に右辺値式(一時オブジェクトを生成する式)を用いることはできる?
コード(1)
// main.cpp #include <cmath> int main() { double &a = sqrt(2.0); }
コンパイルエラー
$ g++ main.cpp main.cpp: In function 'int main()': main.cpp:6: error: invalid initialization of non-const reference of type 'double&' from a temporary of type 'double'
コード(2)
// main.cpp #include <iostream> void sub(int &a) { std::cout << a << std::endl; } int main() { sub(1); }
コンパイルエラー
$ g++ main.cpp main.cpp: In function 'int main()': main.cpp:11: error: invalid initialization of non-const reference of type 'int&' from a temporary of type 'int' main.cpp:4: error: in passing argument 1 of 'void sub(int&)'
答え
できない
解説
右辺値は一時的なオブジェクトであり、非 const 参照によって値を書き換えられる意味がない
もちろん、 const 参照は右辺値を参照することができる
long 型非 const 参照の初期化子に、 int 型の式を用いることはできる?
コード(1)
// main.cpp int main() { int a = 0; long &b = a; }
コンパイルエラー
$ g++ main.cpp main.cpp: In function 'int main()': main.cpp:5: error: invalid initialization of reference of type 'long int&' from expression of type 'int'
コード(2)
// main.cpp #include <iostream> void sub(long &a) { std::cout << a << std::endl; } int main() { int a = 0; sub(a); }
コンパイルエラー
$ g++ main.cpp main.cpp: In function 'int main()': main.cpp:12: error: invalid initialization of reference of type 'long int&' from expression of type 'int' main.cpp:4: error: in passing argument 1 of 'void sub(long int&)'
答え
できない
解説
もし、非 const 参照の初期化子に違う型の式を用いることができたとしても、結局以下の問題に行き着く
- 型が違うので、暗黙の型変換が必要
- 暗黙の型変換は、右辺値(一時オブジェクト)を生成する
- 非 const 参照は、右辺値を参照することができない
const 参照は右辺値を参照することができるので、異なる型の式を初期化子に用いることができる