C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[5]: ADL ってどこまで効くの?


(過去ログ 55 を表示中)

[トピック内 9 記事 (1 - 9 表示)]  << 0 >>

■30859 / inTopicNo.1)  ADL ってどこまで効くの?
  
□投稿者/ 774RR (277回)-(2009/01/08(Thu) 13:33:43)

分類:[C/C++] 

個人的に納得がいかないのでどなたか解説していただけると幸甚の至り。

うまくいく例
typedef std::string value_type; // ここをいろいろ差し替える予定がある
typedef std::vector<value_type> container_type; // list になる可能性がある
// value_type を出力する先が cout/wcout 両方になる可能性があるので basic_ostream で実装
// このオレオレ operator<< は当然無名名前空間においてあり std 内ではない
template<typename charT, typename Traits>
std::basic_ostream<charT, Traits>& operator<<(std::basic_ostream<charT, Traits>& s,
                                              const value_type& v) {
    return s; // 例なので何も出力しなくていい
}
int main() {
    container_type c;
    // value_type を cout に出力したい (将来的には wcout になる可能性あり) 
    std::copy(c.begin(), c.end(), std::ostream_iterator<value_type>(std::cout, "\n"));
}
これは VC++(2005) gcc-4.2.2 とも期待通りの動作をする。
期待通りとは、 ostream_iterator がちゃんとオレオレ operator<< を見つけ
コンパイル・リンクでき、実行できる(この例では何も出力されない)、ということ。

うまくいかない例
typedef std::pair<std::string, std::string> value_type; // 他はすべて同一
とすると ostream_iterator がオレオレ operator<< を見つけられなくなってしまう
ADL が効いていないというべきか、効きすぎているといべきか?
オレオレ operator<< を namespace std 内で定義するとうまくいくので (違反だけど)

なぜ、無名名前空間に配置したオレオレ operator<< が
前者<std::string> では見つかり後者<std::pair<...> > では見つからないの?

引用返信 編集キー/
■30863 / inTopicNo.2)  Re[1]: ADL ってどこまで効くの?
□投稿者/ アキラ (146回)-(2009/01/08(Thu) 14:13:59)
アキラ さんの Web サイト
No30859 (774RR さん) に返信

std::string s;
std::cout << s << std::endl;

と同じで、std::ostream_iteratorにstd::coutを渡してるからstd名前空間の
operator<<がルックアップされるんじゃないかと。

引用返信 編集キー/
■30864 / inTopicNo.3)  Re[2]: ADL ってどこまで効くの?
□投稿者/ アキラ (147回)-(2009/01/08(Thu) 14:15:56)
アキラ さんの Web サイト
2009/01/08(Thu) 14:19:24 編集(投稿者)

No30863 (アキラ さん) に返信
> ■No30859 (774RR さん) に返信
>
> std::string s;
> std::cout << s << std::endl;
>
> と同じで、std::ostream_iteratorにstd::coutを渡してるからstd名前空間の
> operator<<がルックアップされるんじゃないかと。

あれ、ちがう。
この場合はoperator<<に渡してるpairがstd名前空間のクラスだからかな。

ostream_iterator内で
cout << p << "\n";
となってたらpの名前空間を探索しにいくのでそのせいでstd::pairのstd名前空間を探しにいくのかな、と。
引用返信 編集キー/
■30865 / inTopicNo.4)  Re[1]: ADL ってどこまで効くの?
□投稿者/ uskz (3回)-(2009/01/08(Thu) 14:30:22)
uskz さんの Web サイト
2009/01/08(Thu) 14:58:39 編集(投稿者)
2009/01/08(Thu) 14:43:48 編集(投稿者)

No30859 (774RR さん) に返信

3.4.2 ¶2の
>Typedef names and using-declarations used to specify the types do not contribute to this set.
が理由だと思います.
typedef std::string value_type;の場合コンパイルが通るのは,std名前空間のbasic_stringに対するoperator<<が(ordinary lookupによって)見つかっているからです.(cにstd::string型の要素を追加してあげれば分かると思います)
後者は例えば,
struct value_type :
std::pair<std::string, std::string>
{ };
なら無名名前空間のoperator<<がADLによって見つかります.
引用返信 編集キー/
■30873 / inTopicNo.5)  Re[2]: ADL ってどこまで効くの?
□投稿者/ 774RR (278回)-(2009/01/08(Thu) 15:06:53)
なるほど。最初の例で書いた typedef std::string value_type; の場合は確かに
オレオレ operator<< の template を丸ごと削除してもコンパイル通ってしまいました。
俺の知らないうちに ADL が std::operator を見つけてしまっていて、
オレオレ 無名名前空間::operator は使われていないのですな。

struct value_type : std::pair<....> {}; とすればいい、んぢゃね?も納得です。

*ですが*

Q1.
「俺は c.push_back(make_pair("a", "b")); と書きたいんぢゃあ!」
というわがままな要件にどう対応すればいいでしょう? (wcout 時に L"a" に直すのは手でやるとして)
struct value_type : std::pair<std::string, std::string> {
    value_type(const std::pair<std::string, std::string>& a) : std::pair<std::string, std::string>(a) {}
};
としたのでは c.push_back(make_pair(string("a"), string("b"))); としなけりゃなりません。

Q2. (まあ Q1 と状況は同じなのですが)
typedef std::pair<...> value_type; が変更できない場合、オレオレ operator<< をどう実装すべきでしょう?
ないしは、実装できるのでしょうか?できないのでしょうか?

引用返信 編集キー/
■30879 / inTopicNo.6)  Re[3]: ADL ってどこまで効くの?
□投稿者/ アキラ (148回)-(2009/01/08(Thu) 15:36:55)
アキラ さんの Web サイト
No30873 (774RR さん) に返信

ちょうど同じ話題がcppllで前に出てましたね。

http://ml.tietew.jp/cppll/cppll/article/12498
引用返信 編集キー/
■30882 / inTopicNo.7)  Re[3]: ADL ってどこまで効くの?
□投稿者/ uskz (5回)-(2009/01/08(Thu) 15:37:39)
uskz さんの Web サイト
No30873 (774RR さん) に返信

> Q1.
> 「俺は c.push_back(make_pair("a", "b")); と書きたいんぢゃあ!」
> というわがままな要件にどう対応すればいいでしょう? (wcout 時に L"a" に直すのは手でやるとして)
> struct value_type : std::pair<std::string, std::string> {
> value_type(const std::pair<std::string, std::string>& a) : std::pair<std::string, std::string>(a) {}
> };
> としたのでは c.push_back(make_pair(string("a"), string("b"))); としなけりゃなりません。

必要なconstructorやobject generatorも用意したstd::pairもどきを適当な名前空間に作って使うくらいしか思いつきません(あるいはすでにあるBoost.FusionやTuple辺りを使う).


> Q2. (まあ Q1 と状況は同じなのですが)
> typedef std::pair<...> value_type; が変更できない場合、オレオレ operator<< をどう実装すべきでしょう?
> ないしは、実装できるのでしょうか?できないのでしょうか?

std名前空間にオーバーロードを追加するのがスマートだと思いますが,規格はそれを許していないのでstd::pairを直接使う限りは難しいように思います.
引用返信 編集キー/
■30886 / inTopicNo.8)  Re[4]: ADL ってどこまで効くの?
□投稿者/ アキラ (149回)-(2009/01/08(Thu) 16:15:08)
アキラ さんの Web サイト
No30882 (uskz さん) に返信

> (あるいはすでにあるBoost.FusionやTuple辺りを使う).

FusionやTupleだとoperator<<ありますからねぇ。

【Boost.Tupleの場合】

#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
#include <string>
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>

int main()
{
    std::vector<boost::tuple<std::string, std::string> > v;

    v.push_back(boost::make_tuple("a", "b"));

    std::copy(v.begin(), v.end(),
        std::ostream_iterator<boost::tuple<std::string, std::string> >(std::cout, "\n"));
}



【Boost.Fusionの場合】

#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
#include <string>
#include <boost/fusion/sequence.hpp>
#include <boost/fusion/include/make_vector.hpp>

int main()
{
    namespace fusion = boost::fusion;

    std::vector<fusion::vector<std::string, std::string> > v;

    v.push_back(fusion::make_vector("a", "b"));

    std::copy(v.begin(), v.end(),
        std::ostream_iterator<fusion::vector<std::string, std::string> >(std::cout, "\n"));
}

引用返信 編集キー/
■30888 / inTopicNo.9)  Re[5]: ADL ってどこまで効くの?
□投稿者/ 774RR (280回)-(2009/01/08(Thu) 16:40:49)
当方でも tuple/fusion 使ってみましたがアキラ氏に先を越されてしまったようです。

でも結局のところ tuple を使うにせよ fusion を使うにせよ、
value_type として直接 pair/tuple/fusion の typedef (alias) を使っている限り、
ADL によって、採用されるのはライブラリ提供の operator << になってしまうわけっすな。
# まあ、言語仕様の意図するところを汲むに、そうならざるを得ないわね

オレオレ operator << を使いたいのであれば、ライブラリの提供する型 (の alias) を
*直接* 使わない、しかない、ということですな。
言われてみれば当然の答えになってしまうわけですが。

当たり前すぎて意外な結果であった・・・脳内メモにきっちり残しておこう。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -