質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Windows 10

Windows 10は、マイクロソフト社がリリースしたOSです。Modern UIを標準画面にした8.1から、10では再びデスクトップ主体に戻され、UIも変更されています。PCやスマホ、タブレットなど様々なデバイスに幅広く対応していることが特徴です。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

コンパイルエラー

コンパイルのフェーズで生成されるエラーです。よく無効なシンタックスやタイプが含まれているとき発生します。

継承

継承(インヘリタンス)はオブジェクト指向プログラミングに存在するシステムです。継承はオブジェクトが各自定義する必要をなくし、継承元のオブジェクトで定義されている内容を引き継ぎます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

1230閲覧

仮想継承でデフォルトコンストラクタが必要な旨のコンパイルエラーが起こる

tails

総合スコア22

Windows 10

Windows 10は、マイクロソフト社がリリースしたOSです。Modern UIを標準画面にした8.1から、10では再びデスクトップ主体に戻され、UIも変更されています。PCやスマホ、タブレットなど様々なデバイスに幅広く対応していることが特徴です。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

コンパイルエラー

コンパイルのフェーズで生成されるエラーです。よく無効なシンタックスやタイプが含まれているとき発生します。

継承

継承(インヘリタンス)はオブジェクト指向プログラミングに存在するシステムです。継承はオブジェクトが各自定義する必要をなくし、継承元のオブジェクトで定義されている内容を引き継ぎます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

2クリップ

投稿2021/10/16 12:04

質問

以下のソースコードで、コンパイルエラーが発生します。
なにが問題なのか分からないのですが、エラーの原因を教えてください。
…バグですか?

C++

1template <class... Args> 2struct vbase { 3 template <class T> 4 vbase(T &&another); 5 6 virtual ~vbase(); 7}; 8 9struct derived1 : virtual vbase<int, double> { 10 using base = vbase<int, double>; 11 using base::base; 12}; 13 14struct derived2 : derived1 { 15 using derived1::derived1; 16}; 17 18int main() { 19 derived2{0}; 20}

エラーメッセージ

(ファイル名) (ファイル名)(21): error C2512: 'vbase<int,double>::vbase': クラス、構造体、共用体に既定のコンストラクターがありません。 (ファイル名)(19): note: コンパイル対象の関数 テンプレート インスタンス化 'derived2::derived2<int>(int &&)' のリファレンスを確認してください

環境

Visual Studio 2019
Windows 10
コンパイルオプション: /std:c++17

試したこと

以下のいずれかを行うと、上記のコンパイルエラーは発生しなくなります。(定義がないので、リンクエラーは発生しますが。)

  • GCC でコンパイルする
  • Clang でコンパイルする
  • virtual を削除
  • vbase のテンプレートパラメータを単に削除して、テンプレートクラスではなく、普通のクラスにする
  • derived2{0} ではなく derived1{0} とする

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

C++14 までは継承コンストラクタの理屈は派生したクラスにコンストラクタが追加で注入されることになっていました。 C++17 以降の理屈では基底クラスのコンストラクタを名前探索で発見できることにするというルールに変更されています。

GCC では古い規則に沿って解釈するオプション -fno-new-inheriting-ctors を提供しており、このオプションを有効にすると最新の GCC でも今回の質問で提示されたコードはエラーになります。

私もきちんとした理解が出来ておらずきちんとした説明が出来ないのですが、 Visual Studio では古い理屈のままになっていると思われます。 C++17 を指定してエラーになるのは現時点ではコンパイラのバグであろうとは言えるものの、過去の C++ ではエラーになるのが正しい挙動だった可能性があります。

ちなみに C++17 で理屈が変更されたと上述しましたが、 C++ では欠陥報告という制度があります。 仕様の矛盾や深刻な問題を次の仕様更新を待たずに過去に遡って修正する場合もあるという制度です。 継承コンストラクタの挙動の変更は P0136R1 が C++11 から適用されたことになったので、「今の C++11」では古い理屈は無かったことになってます。

根拠になるはずの仕様が変更されることがあるので事情を追うのが難しくてよくわからないですね。

投稿2021/10/17 09:07

SaitoAtsushi

総合スコア5444

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tails

2021/10/17 17:20

なるほど… ありがとうございます。 つまり、過去の inheriting constructors の仕様では、 struct derived2 : derived1 { using derived1::derived1; }; は struct derived2 : derived1 { template <class T> derived2(T &&another) : derived1(std::forward<T>(another)) {} }; のようになるから、仮想基底クラスである vbase を(暗黙に)デフォルトコンストラクトしようとして、コンパイルエラーになるということでしょうか。 一方、現在の仕様では、vbase<T>::vbase(T&&) を直接呼んで構築できるので、無事、コンパイル出来なければいけないと理解しましたが、正しいでしょうか。
SaitoAtsushi

2021/10/17 17:38

はい。 おそらくそれでよいと思います。 関連する規則として、デフォルトの定義が使われるルールになっている場合にデフォルト定義をあてはめることができなければ存在しないという形でデフォルト定義をすることがあります。 この場合でいえば derived2::derived2 のデフォルト定義に失敗したので単にそれは存在しなかった扱いになるということです。 この規則の重要な点はクラスの定義自体は成功するという点です。 コンストラクタを呼び出そうとした段階になって初めてそのようなものは無かったというエラーになります。
tails

2021/10/18 05:01

なるほど!バッチリ分かりました。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問