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

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

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

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

Q&A

解決済

2回答

2829閲覧

決して呼ばれないはずのデフォルトコンストラクタは、いつ呼ばれている?

asobinin

総合スコア69

C++

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

0グッド

0クリップ

投稿2019/11/02 16:19

編集2019/11/02 16:28

C++の多重継承を利用して自作のプロパティをつくっていたのですが、どこでも呼んでいないはずのデフォルトコンストラクタが呼ばれてしまい、エラーとなってしまっています。
試しにnone_options_property() : m_ref_value(a) { std::cout << "DEFAULT CONSTRUCTOR" << std::endl; }でテストしてみても、"DEFAULT CONSTRUCTOR"が表示されることはありませんでした。
一体どの箇所でデフォルトコンストラクタが呼ばれてしまっているのでしょうか?

実行環境:
OS Windows10 home
コンパイラ:
Visual Studio2019
エラー文 C2280 'asobi::detail::property_options<T,asobi::options::get,asobi::options::set>::property_options(void)': 削除された関数を参照しようとしています

GCC 8.2.0
エラー文(一部抜粋) In function 'int main()':
test.cpp:16:52: error: use of deleted function 'asobi::property<int, asobi::options::get, asobi::options::set>::property(int&) [inherited from asobi::detail::none_options_property<int>]'
asobi::property<int, GET_OP, SET_OP> value(m_value);


コードが長くなってしまいますが、すべてのコントラスタはproperty_detail.hppの中の基底クラスであるnone_options_propertyのコントラスタを継承しています。

Cpp

1// main.cpp 2#include "asobi/Cpp/property.hpp" 3int main() 4{ 5 int m_value = 810; 6 7 asobi::property<decltype(m_value), FULL_OP> value(m_value); 8 9 return 0; 10}

Cpp

1// property.hpp 2#pragma once 3#define ASOBI_PROPERTY 4 5#include "detail/property_detail.hpp" 6 7#define GET_OP asobi::options::get 8#define SET_OP asobi::options::set 9#define FULL_OP asobi::options::get, asobi::options::set 10 11namespace asobi { 12 13// property 14template <class T, class... Options> 15class property final : virtual public detail::none_options_property<T>, public detail::property_options<T, Options...> { 16public: 17 using detail::none_options_property<T>::none_options_property; 18}; 19 20} // namespace asobi 21

Cpp

1// property_detail.hpp 2#pragma once 3#define ASOBI_DETAIL_PROPERTY_DETAIL 4 5#include <type_traits> 6#include <iostream> 7#include "../type_operation.hpp" 8 9 10int a = 0; // テスト用 11 12namespace asobi { 13 14namespace options { 15 struct get {}; 16 struct set {}; 17} 18 19namespace detail { 20 // 非アクセスプロパティ 21 template <class T> 22 class none_options_property { 23 protected: // member variable 24 T& m_ref_value; 25 public: // constructor, destructor 26 none_options_property() = delete; 27 //none_options_property() : m_ref_value(a) { std::cout << "DEFAULT CONSTRUCTOR" << std::endl; } 28 none_options_property(none_options_property& other) = delete; 29 none_options_property(T& lvalue) : m_ref_value(lvalue) { std::cout << "NOMAL CONSTRUCTOR" << std::endl; } 30 virtual ~none_options_property() = default; 31 }; 32 33 // getオプション付きプロパティ 34 template <class T> 35 class get_options_property : virtual public none_options_property<T> { 36 public: // constructor, destructor 37 using none_options_property<T>::none_options_property; 38 public: // functions 39 inline const T& get() const { return this->m_ref_value; } 40 inline operator const T& () const { return this->m_ref_value; } 41 }; 42 43 // setオプション付きプロパティ 44 template <class T> 45 class set_options_property : virtual public none_options_property<T> { 46 public: // constructor, destructor 47 using none_options_property<T>::none_options_property; 48 public: // functions 49 inline auto& set(T&& value) { this->m_ref_value = std::move(value); return *this; } 50 inline auto& set(const T& value) { this->m_ref_value = value; return *this; } 51 inline auto& operator =(T&& value) { this->m_ref_value = std::move(value); return *this; } 52 inline auto& operator =(const T& value) { this->m_ref_value = value; return *this; } 53 inline auto& operator +=(T&& value) { this->m_ref_value += value; return *this; } 54 inline auto& operator +=(const T& value) { this->m_ref_value += value; return *this; } 55 inline auto& operator -=(T&& value) { this->m_ref_value -= value; return *this; } 56 inline auto& operator -=(const T& value) { this->m_ref_value -= value; return *this; } 57 inline auto& operator *=(T&& value) { this->m_ref_value *= value; return *this; } 58 inline auto& operator *=(const T& value) { this->m_ref_value *= value; return *this; } 59 inline auto& operator /=(T&& value) { this->m_ref_value /= value; return *this; } 60 inline auto& operator /=(const T& value) { this->m_ref_value /= value; return *this; } 61 inline auto& operator |=(T&& value) { this->m_ref_value |= value; return *this; } 62 inline auto& operator |=(const T& value) { this->m_ref_value |= value; return *this; } 63 inline auto& operator &=(T&& value) { this->m_ref_value &= value; return *this; } 64 inline auto& operator &=(const T& value) { this->m_ref_value &= value; return *this; } 65 inline auto& operator ^=(T&& value) { this->m_ref_value ^= value; return *this; } 66 inline auto& operator ^=(const T& value) { this->m_ref_value ^= value; return *this; } 67 }; 68 69 // getがあるか 70 template<class T, class... Options> 71 struct has_get : public std::conditional<find_type<options::get, Options...>::value, get_options_property<T>, nothing>::type {}; 72 73 // setがあるか 74 template<class T, class... Options> 75 struct has_set : public std::conditional<find_type<options::set, Options...>::value, set_options_property<T>, nothing>::type {}; 76 77 // propertyが継承するもの 78 template <class T, class... Options> 79 struct property_options 80 : public has_get<T, Options...>, 81 public has_set<T, Options...> 82 {}; 83 84} // namespace detail 85 86} // namespace asobi 87

Cpp

1// type_operation.hpp 2#pragma once 3#define ASOBI_TYPE_OPERATION 4 5#include <tuple> 6#include <type_traits> 7 8namespace asobi { 9 10namespace detail { 11 struct nothing {}; 12} 13 14// find_type 15// 型リストの中から、見つけたい型が含まれているかをチェックする 16// value・・・含まれている場合:true 含まれていない場合:false 17namespace detail { 18 template <class FindType, class List> 19 struct find_type_impl; 20 21 template <class FindType, class Thead, class... Ttail> 22 struct find_type_impl<FindType, std::tuple<Thead, Ttail...>> { 23 static const bool value = 24 std::is_same<FindType, Thead>::value ? 25 true : 26 find_type_impl<FindType, std::tuple<Ttail...>>::value; 27 }; 28 29 template <class FindType> 30 struct find_type_impl<FindType, std::tuple<>> { 31 static const bool value = false; 32 }; 33} 34template <class FindType, class... List> 35struct find_type { 36 static const bool value = detail::find_type_impl<FindType, std::tuple<List...>>::value; 37}; 38 39} // namespace my 40

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

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

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

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

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

guest

回答2

0

ベストアンサー

property -> property_options -> has_set または has_get -> set_options_property -> none_options_property の継承経路をたどっていくと、property_optionsから以降は、すべてデフォルトコンストラクタで初期化されています。ということは、set_options_propertyを実体化するときに、たとえ使われなくても、親クラスのnone_options_propertyのデフォルトコンストラクタを呼び出すコードを生成していると思います。

投稿2019/11/02 22:48

Bearded-Ockham

総合スコア430

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

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

asobinin

2019/11/03 04:43

なるほど、確かにhas_getなどで指定しているget_options_property<T>などでは、コンストラクタを指定しておりませんでした。 こんなところにメタプログラミングの副作用があったとは思いもよりませんでした。
guest

0

こんにちは。

ソースが長いので読めていませんが、そのような現象が起こることはありえます。
最適化によりデフォルト・コンストラクタは呼ばれないが、構文上は呼び出されるような時などがあります。

今回のケースでは、テンプレート・メタ・プログラミングの中で none_options_propertyやそれを継承したクラスを実体化できるかどうか判定しているところはないでしょうか? その実体化のテスト時に引数指定されていないとありえそうな気もします。(あまり自信はないのですが。)
property_optionsのhas_get、has_set継承をコメントアウトするとエラーがでなくなるので、この辺りがあやしそうです。

投稿2019/11/02 16:45

編集2019/11/02 18:30
Chironian

総合スコア23272

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問