おそらく基本的なところなのですが
参照を参照で渡すのはNG…?
という記述をどっかで見たような見なかったような気がするのですが
再度確認しようと思うも見つからず。
気のせいかもしれません。
または
そのときの文章では「参照」という言葉が別の意味で使われていたかもしれませんが
以下のように、左辺値参照を左辺値参照渡しするコードはconst参照、非const参照問わず規格上OKでしたっけ?
#include <stdio.h>
void func(int& n){
if ( n%7 ){ n+=9; func(n); }
else return;
}
int main(void){
int i = 1;
func(i);
printf( "%d", i );
return 0;
}
No.2ベストアンサー
- 回答日時:
あ~, 「『int への参照』の参照は NG」で誤解させちゃった.... すみません, これはおかしいです. 参照への参照は「作れない」, といった方が適切でした. ほかにも, 「参照へのポインタ」とか「参照の配列」も作れません.
と冒頭で断っておいて, と.
あんまりまじめに参照を使うこともない (関数の引数/返り値以外ではあんまり使ってないなぁ) のでやっぱり規格 (FDIS) を見たりするわけですが, 実は 7 は OK だったりします.
T が「typedef, テンプレート引数または decltype」で参照を含む場合には T& あるいは T&& も合法です. その場合, T&& なら T と同じ参照を表し, T& は強制的に左辺値参照となります. 7 の場合 T = int& で T& という形ですから T& = int& です (この場合は T&& も int&).
質問文のコードを合法にしないとまずいのは, operator = をオーバーロードするときを考えればわかると思います. つまり, X::operator = はたいてい
X &X::operator =(const X &)
のように宣言しますよね. とすると,
X a, b, c;
a = b = c;
とやっちゃうと
a.operator =(b.operator =(c))
と同じで「b.operator =(c) が返す参照をそのまま a.operator = に参照引数として渡す」ことになります. 「参照を参照で渡す」のを NG にしちゃうとこれも NG になってしまいます.
この回答への補足
あ、もしかして項目7が「OK」なのって「C++11であれば」ってことでしょうか?
そうなると下の
std::bind2ndやstd::listの件に関しては別の個所が問題なのかな…??
あれ?でもやっぱりちょっとおかしいような
試すの忘れてたのでVC++2008(C++03のはず)で試したら
7は通りませんでした。
2010では通りました。
この「通るか通らないか」は「準拠状況込み」の話なんでしょうかね。
ありがとうございます♪
>「参照へのポインタ」とか「参照の配列」も作れません.
そのへんはOKです。たぶんw
>7 の場合 T = int& で T& という形ですから T& = int& です (この場合は T&& も int&).
あ、そうなるんですか。
それはどの部分に書いてありましたでしょうか?(あるいは基本的なことなんでしょうか)
>質問文のコードを合法にしないとまずいのは~
なるほど、基本的な使い方では問題はないということですね。
う~~んしかし
http://boost.cppll.jp/HEAD/libs/functional/binde …
(↑たぶん文字エンコーディングは 日本語(EUC-JP))
を要約して
#include <iostream>
#include <vector>
int main(void){
struct Foo{ void bar(std::ostream&){} };
std::bind2nd(std::mem_fun_ref(&Foo::bar), std::cout);
}
みたいな感じでコンパイルエラーになったり
http://www.devx.com/tips/Tip/13219
を要約して
#include <list>
struct Node;
std::list <Node&> ln;
int main(void){}
でコンパイルエラーになる理由が、追いまくってみたものの、現状
良く分かっていません。
typedef typename なんとか::メンバ& 新しい型名;
みたいな部分が絡んでる?のかな?と思ったり思わなかったりなのですが
下の7の例が
T&& → int&
となって、こっちが出来なくなる理由が分かりません。(あるいは別の部分が問題?)
これらはどういう違い、あるいは理由があるんでしょうか?
(なにもインクルードせずに10行以内程度で再現できるコードが出来ればそれをみたいです)
No.3
- 回答日時:
ざっと調べてみましたが, 11 で導入された可能性があります. 98 を斜め読みしてみたものの, 対応する文言は見つからず.
std::list については要素が CopyConstructible でなければならない (つまり「& でアドレスが取れる」必要がある) ので参照は無理じゃないかなぁ.
この回答への補足
おお
VC++2008でみれました
typedef int& IR;
int a = 0;
IR b = a;
IR& c = b;
error C2529: 'c' : 参照への参照は無効です。
(とerror C2440: '初期化中' : 'int' から 'IR (&)' に変換できません)
とか
template <class T> struct DATA{ T& t; };
typedef int& IR;
int a = 0;
IR b = a;
DATA<IR> d = {b};
error C2529: 't' : 参照への参照は無効です。
error C2440: '初期化中' : 'int' から 'IR (&)' に変換できません。
あー、こうしてみると
やっぱ「参照の参照」って
あくまで型の話ってことでOKですね。
なお、これらのコードはVC++2010なら通りました。
>std::list については要素が CopyConstructible でなければならない (つまり「& でアドレスが取れる」必要がある) ので参照は無理じゃないかなぁ.
なるほど、参照へのポインタが無理なのでってことですね。
綿密に調べてみました。
4段階の継承とallocatorを持ってて
大変でしたが
整理したときにミスってなければ
最終的、具体的には、これらの理由は見つけました。
template<class T >
struct list {
T* Alloc(){return (T*)operator new( sizeof(T) );}
struct NODE { T _Myval; } head;
};
struct Node {};
list<Node&> ln; //list<Node*> ln; や list<Node> ln;なら可
確かに
これは単純に、無理ですねw
でも
「A Reference to a Reference is Illegal」
が絡む箇所あったかな?
と思ったので、2008でも確認してみたら
2010ではエラー数6なのに対して
エラー 19、警告 18
と、大幅に内容に開きがありました。
また
#include <iostream>
#include <vector>
int main(void){
struct Foo{ void bar(std::ostream&){} };
std::bind2nd(std::mem_fun_ref(&Foo::bar), std::cout);
}
の方は
2010だと
error C2440: '初期化中' : 'const std::ostream' から 'std::basic_ostream<_Elem,_Traits> &' に変換できません。
一つのみなのに対し(しかも↑の内容そのものになってしまうなら確かに当然無理)
2008ではエラー 4つでした。
これらから、まだ記述を見つけてないだけだとしたら
2008と2010では準拠レベルが違うか、C++11で「参照の参照は参照」が正式に公認になった
もし言語仕様で明確に言及されてないようなら、VC++2010の機転か何かの可能性がある
ただし問題となり得る「参照の参照」というのは、「やはりテンプレートかtypedefとかのメタプログラミング関連?」
でもって
とりあえず
質問文の内容や
項目6の内容や
struct X{
X &X::operator=(const X &){ return* this; }
static void f(){
X a, b, c; a = b = c;
}
};
がC++11でなくても合法
というのは確定的なので
ふつーに自分でそんなにややこしくない使い方する分には
何ら問題なさ気、って判断しといていい、でしょうかね。
No.1
- 回答日時:
あ, 今 C++11 の FDIS 見てたらなんとなく言いたいことがわかった気がする.
「参照を参照型の引数として関数に渡す」ことはまったく問題ありません... というか, それは否定されるといろいろめんどくさい.
「参照の参照」は作れません. つまり
int への参照
はできる (int& だ) が
「int への参照」の参照
は NG.
どうもありがとうございます♪
あ~、そんな感じの書かれ方だった気がします。
でもそんときも「コードを見なかったんで正確に分かんなかった」んですがw
コード込みでしっかり確認しておきたいので
C++11込みだと
これらの認識で全部OKでしょうか?
1.
int&& a = 1;
もし「参照の参照を意図したい表記」として
こういう風に書くと、この場合C++03では「NGではなく出来ない。」
C++11では文法上OKになるが、参照の参照ではなく、この場合右辺値参照となる。
2.
int a = 1;
int&& b = a;
右辺値参照には左辺値をそのまま代入出来ない。C++11でも不正。
3.
int a = 1;
int&& b = std::move(a);
C++11では合法。
4.
int& a = 1;
非const参照は右辺値で初期化できない。
どちらでもエラー。
5.
const int& a = 1;
あるいは
template <class T> T func(T&& t){ return t+1; }
const int& a = func(1);
など
const参照の場合は、特別に初期化に右辺値をとれる。
生存期間はこの参照のそれと同じ。
6.
void func(const int& i){ printf( "%d", i ); }
int i=6;
int& a = i;
func(a);
質問文のコードと同じく、まったくの合法、ということになる。
7.
template <class T> void func(T& t){ ++t; }
int a = 9;
func<int&>( a );
printf("%d", a );
tの型は「int&の参照」となるので
これがNG。
ということでしょうか?
つまり「参照の参照は"NG"("不可"ではなく)」
と言われるときの「参照の参照」とは
こういう風にテンプレートを使った時の、それに限る
という事で大丈夫でしょうかね?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・一回も披露したことのない豆知識
- ・これ何て呼びますか
- ・チョコミントアイス
- ・初めて自分の家と他人の家が違う、と意識した時
- ・「これはヤバかったな」という遅刻エピソード
- ・これ何て呼びますか Part2
- ・許せない心理テスト
- ・この人頭いいなと思ったエピソード
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・あなたの習慣について教えてください!!
- ・ハマっている「お菓子」を教えて!
- ・高校三年生の合唱祭で何を歌いましたか?
- ・【大喜利】【投稿~11/1】 存在しそうで存在しないモノマネ芸人の名前を教えてください
- ・好きなおでんの具材ドラフト会議しましょう
- ・餃子を食べるとき、何をつけますか?
- ・あなたの「必」の書き順を教えてください
- ・ギリギリ行けるお一人様のライン
- ・10代と話して驚いたこと
- ・家の中でのこだわりスペースはどこですか?
- ・つい集めてしまうものはなんですか?
- ・自分のセンスや笑いの好みに影響を受けた作品を教えて
- ・【お題】引っかけ問題(締め切り10月27日(日)23時)
- ・大人になっても苦手な食べ物、ありますか?
- ・14歳の自分に衝撃の事実を告げてください
- ・架空の映画のネタバレレビュー
- ・「お昼の放送」の思い出
- ・昨日見た夢を教えて下さい
- ・ちょっと先の未来クイズ第4問
- ・【大喜利】【投稿~10/21(月)】買ったばかりの自転車を分解してひと言
- ・メモのコツを教えてください!
- ・CDの保有枚数を教えてください
- ・ホテルを選ぶとき、これだけは譲れない条件TOP3は?
- ・家・車以外で、人生で一番奮発した買い物
- ・人生最悪の忘れ物
- ・【コナン30周年】嘘でしょ!?と思った○○周年を教えて【ハルヒ20周年】
- ・10秒目をつむったら…
- ・人生のプチ美学を教えてください!!
- ・あなたの習慣について教えてください!!
- ・都道府県穴埋めゲーム
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
visualstudio C# テキストボッ...
-
DWORDの実際の型は何でしょうか
-
long型の定数の末尾にLを付ける...
-
コンパイルすると error C1083 ...
-
2重定義って??
-
関数の実体定義にヘッダファイ...
-
構造体の要素すべてに対する四...
-
エラー「invalid conversion fr...
-
intとINTの違いは?
-
C++のfor文について
-
戻り値の型??
-
APIENTRY と WINAPI
-
変数の型を定義しなかった場合...
-
namespace定義の使い方
-
ハンドルされていない例外が発...
-
512Lや1024L等の「L」について
-
プログラムの中で別のmainを呼...
-
C++でboolにintの値を代入する...
-
Aの値からBの値を除するとは??
-
Enterキーを押されたら次の処理...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
DWORDの実際の型は何でしょうか
-
C++のfor文について
-
2重定義って??
-
visualstudio C# テキストボッ...
-
long型の定数の末尾にLを付ける...
-
typedef enumの使い方を教えて...
-
C++でboolにintの値を代入する...
-
プログラムの中で別のmainを呼...
-
構造体の要素すべてに対する四...
-
変数の型を定義しなかった場合...
-
intとINTの違いは?
-
main.c:7:43: warning: implici...
-
【#define】 defineで定義した...
-
構造体の宣言でエラーが出ます。
-
エラー「invalid conversion fr...
-
ハンドルされていない例外が発...
-
関数の実体定義にヘッダファイ...
-
void func( void )について
-
sshdログの意味
-
C言語での方向キー入力判定
おすすめ情報