🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C++

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

Q&A

解決済

2回答

887閲覧

const属性を付してポインタへのポインタを取得するテンプレートクラスメンバ関数の作り方について

jbe00214

総合スコア63

C++

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

0グッド

0クリップ

投稿2021/03/13 00:24

編集2021/03/13 00:29

前提・実現したいこと

プリミティブなデータへのポインタを管理するvectorを含むクラス(Boo)から,ポインタへのポインタを管理するクラス(Foo)を取得する際に,const属性をつけて取得する方法がわかりません。コード例は以下のとおりです。どなたかお知恵をいただければと思います。
用途としては,Booではデータ管理だけを行い,Fooの方で,ポインタへのポインタを使って操作をすることを考えています。Fooで使う時に,T自体の変更不可を保証した動作にすることが目的です。

発生している問題・エラーメッセージ

Cannot initialize return object of type 'const int **' with an rvalue of type 'const std::__1::vector<int *, std::__1::allocator<int *> >::value_type *' (aka 'int *const *')

該当のソースコード

C++

1#include<vector> 2#include<iostream> 3template<typename T> 4struct Foo{ 5 T** a; 6 Foo( T ** p){a=p;} 7}; 8template<typename T> 9struct Boo{ 10 std::vector<T*> v; 11 const T ** data()const{return v.data();} 12 Foo<const T> get()const { 13 return{data()}; 14 } 15}; 16 17int main(){ 18 Boo<int>b; 19 int a = 10; 20 b.v.emplace_back(&a); 21 auto f = b.get(); 22 std::cout <<**f.a <<'\n'; 23}

補足情報(FW/ツールのバージョンなど)

clang
c++17

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

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

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

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

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

guest

回答2

0

自己解決

C++

1const T ** data()const{return const_cast<const T**>(v.data());}

とすることで解決しました。
get()constで扱うBooのメンバは,T*そのものがconstにならざるを得ないため,v.data()を返す型をそのままでは使えないということがわかりました。Foo<const T>で返すことになるわけですから,欲しいのはT型の変更不可属性であり,const Tのポインタのポインタ型,すなわちdata()が返す型は const T** にならなければいけないわけです。方法としてはconst_castを使うしかないという結論に至りました。これで期待する動作になったので,問題はないと思います。
お騒がせいたしました。

C++

1int c = 10; 2const int* pc= &c; 3const int** ppc=&pc; 4Foo<const int> cf(ppc);

投稿2021/03/13 06:15

jbe00214

総合スコア63

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

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

yumetodo

2021/03/13 07:35

const castなんかせんでもFooクラスのT**を全部T* const*に置換すればいいと思いますが
jbe00214

2021/03/13 09:18

そうでした。この方法もありました。気づきませんでした。アドバイスありがとうございます。
guest

0

そもそも論として次のようなコードを考えます。

#include <type_traits> using T1 = int*; using T2 = const T1*; static_assert(std::is_same_v<T2, int* const*>);

ここでT2int const **ではなくint * const *であることに注意してください。

よってstd::vector::data()の戻り値の型もint * const *です。


で、ところでなんでstd::vectorにポインタを突っ込んでいるのかよくわからないのですが。

投稿2021/03/13 01:51

yumetodo

総合スコア5852

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

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

jbe00214

2021/03/13 04:12

ありがとうございます。std::vector::data()の戻り値の型をint * const *とすると, Fooのコンストラクタも, Foo( T *const* p){a=p;}とすることになるのでしょうか。そうすると,Assigning to 'const int **' from incompatible type 'const int *const *'エラーが出てしまいます。うまくいきません。vectorにポインタを使っている理由は,このコードとは別に本来のTを管理するvector<T>があって,このvectorを維持しておきながら,配列順序を変更したBooがあるというイメージです。Fooを使って元のvector<T>の要素を変更することがあるわけです。ただFooの機能の一部で要素を変更しない場合もあるので,本質問のような仕組みを考えたわけです。
jbe00214

2021/03/13 05:25 編集

get()が返すFooコンストラクタはconst T型だけど,get()のconst属性はT*constというところに根本的な間違いがあるような気がするけど方法がわからない。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問