2016-08-15 5 views
9

ここでは、テストケースです:なぜlexical_castは演算子>>が一致する名前空間にあることを要求しますか?

#include <istream> 
#include <boost/lexical_cast.hpp> 

namespace N { 
    enum class alarm_code_t { 
     BLAH 
    }; 
} 

std::istream& operator>>(std::istream& is, N::alarm_code_t& code) 
{ 
    std::string tmp; 
    is >> tmp; 

    if (tmp == "BLAH") 
     code = N::alarm_code_t::BLAH; 
    else 
     is.setstate(std::ios::failbit); 

    return is; 
} 

int main() 
{ 
    auto code = boost::lexical_cast<N::alarm_code_t>("BLAH"); 
} 

ブーストがあることを主張し、変換を拒否していないoperator>>マッチング:

In file included from /usr/local/include/boost/iterator/iterator_categories.hpp:22:0, 
       from /usr/local/include/boost/iterator/iterator_facade.hpp:14, 
       from /usr/local/include/boost/range/iterator_range_core.hpp:27, 
       from /usr/local/include/boost/lexical_cast.hpp:30, 
       from main.cpp:2: 
/usr/local/include/boost/lexical_cast/detail/converter_lexical.hpp: In instantiation of 'struct boost::detail::deduce_target_char_impl<boost::detail::deduce_character_type_later<N::alarm_code_t> >': 
/usr/local/include/boost/lexical_cast/detail/converter_lexical.hpp:270:89: required from 'struct boost::detail::deduce_target_char<N::alarm_code_t>' 
/usr/local/include/boost/lexical_cast/detail/converter_lexical.hpp:404:92: required from 'struct boost::detail::lexical_cast_stream_traits<const char*, N::alarm_code_t>' 
/usr/local/include/boost/lexical_cast/detail/converter_lexical.hpp:465:15: required from 'struct boost::detail::lexical_converter_impl<N::alarm_code_t, const char*>' 
/usr/local/include/boost/lexical_cast/try_lexical_convert.hpp:174:44: required from 'bool boost::conversion::detail::try_lexical_convert(const Source&, Target&) [with Target = N::alarm_code_t; Source = char [5]]' 
/usr/local/include/boost/lexical_cast.hpp:42:60: required from 'Target boost::lexical_cast(const Source&) [with Target = N::alarm_code_t; Source = char [5]]' 
main.cpp:25:60: required from here 
/usr/local/include/boost/lexical_cast/detail/converter_lexical.hpp:243:13: error: static assertion failed: Target type is neither std::istream`able nor std::wistream`able 
      BOOST_STATIC_ASSERT_MSG((result_t::value || boost::has_right_shift<std::basic_istream<wchar_t>, T >::value), 

demo

はしかし、コードは宣伝通りに動作したときに、私を宣言/定義operator>>内部名前空間N

なぜですか?それ以外の場合にルックアップが失敗するのはなぜですか?

+7

ボグ標準のADLの問題? –

+0

@ T.C .:えええええええええええええええええええええええええええええええええばグローバルネームスペースは検索されず、この特定の '演算子>>'が見つかりませんでしたか?しかし、私は 'N 'の中に別の' operator 'を持っていません。または、実際には、いずれか。私はADLがどこに来るのかわからない。 –

+1

あなたの '演算子' 'の第2のパラメータ型が' N :: alarm_code_t'であるので、 'N'は関連する名前空間であり演算子の定義が検索されるので、ADLが入ります。 – Praetorian

答えて

13

operator>>に呼がboost::lexical_cast<>関数テンプレートから作られているので、operator>>に2番目の引数がdependent nameである:

参照は、参照で説明したように

で使用依存名のルックアップを支配テンプレート引数が既知になるまでテンプレートが延期される。このとき、テンプレート引数は既知であり、その時には

  • 非ADL loo KUPは

  • ADLは、テンプレート定義コンテキストテンプレートのインスタンス化コンテキストの両方から見える外部結合を持つ関数宣言を調べテンプレート定義コンテキストから見える外部結合を持つ関数宣言を調べ

(言い換えれば、テンプレート定義後に新しい関数宣言を追加しても、ADL以外では表示されません)...このルールの目的は、テンプレートのODR違反を防ぐためですインスタンス化。

つまり、テンプレートインスタンス化コンテキストから非ADLルックアップは実行されません。

呼び出しの引数のいずれもグローバル名前空間との関連付けを持たないため、グローバル名前空間は考慮されません。

operator>>(std::istream& is, N::alarm_code_t& code)は、名前空間Nで宣言されていません。したがって、ADLは見つかりません。


これらの名前検索の奇妙さはN1691 Explicit Namespacesに記載されています。

4

私は例を少し書き直し:今すぐ

namespace N { 
    struct AC {}; 
} 

namespace FakeBoost { 

    template <typename T> 
    void fake_cast(T t) { 
     fake_operator(t); 
    } 

} 

void fake_operator(N::AC ac) { 
} 

int main(){ 
    FakeBoost::fake_cast(N::AC()); 
} 

N::ACためfake_operatorFakeBoostで定義されていない、それはまた、(そうなしADL)Nで定義されていないので、fake_castはそれを見つけることができません。

エラーメッセージは、(boostのために)ちょっとしたものです。私の例としては、

main.cpp: In instantiation of 'void FakeBoost::fake_cast(T) [with T = N::AC]': 
main.cpp:19:33: required from here 
main.cpp:10:22: error: 'fake_operator' was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive] 
    fake_operator(t); 
    ~~~~~~~~~~~~~^~~ 
main.cpp:14:6: note: 'void fake_operator(N::AC)' declared here, later in the translation unit 
void fake_operator(N::AC ac) { 
     ^~~~~~~~~~~~~ 

多くのことを説明しています。

+1

"ブーストで' using namespace std; 'を使うため、' operator >> 'の他のオーバーロードが見つかりました。やあ、何? –

+1

@ T.C。それは間違っているようですが、私は実際に '' 'を呼び出す文脈で' '名前空間std'を使用していません。https://github.com/boostorg/lexical_cast/blob/develop/include/boost/lexical_cast/detail/converter_lexical_streams.hpp #L601 –

+1

@TCノートを削除しました。これは実際には他のコンテキストで使用されています。しかし、彼らは 'std'を扱います - あなたが' std'に(科学のためだけに) 'fake_operator'を置くなら、それは働き始めます –

2

operator>>namespace boostに見つかると、囲まれた名前空間の検索が停止します。ただし、ADLルックアップも行います。

#include <iostream> 

namespace B{ 
    struct bar {}; 
} 

void foo(B::bar) { 
    std::cout << "foobar!\n"; 
} 


namespace A{ 
    void foo(int) {} 

    template<class T> 
    void do_foo(T t) { 
    foo(t); 
    } 
} 


int main() { 
    A::do_foo(B::bar{}); 
} 

上記は構築されません。

コメントアウトvoid foo(int) {}とコードがコンパイルされます。あなたの問題は同じです。ちょうどfooの代わりに演算子で。

基本的に、ADLで見つからない演算子は非常に壊れやすいので、その演算子に頼ることはできません。

live example

の変化は、「すでにfooという名前の関数を(見つかった場合順序はまた、(foo(B::bar)do_foo関数の後に定義されている場合、それはdo_fooの定義の時点でも、ADLによって発見することができない)のルックアップを破る含ま。またはoperator>>)これは、テンプレート内の非ADL検索が脆弱であり、多くの方法のほんの一部であり、それを破壊しない要するに

:。

#include <iostream> 


namespace A{ 

//無効のfoo(int型){}

template<class T> 
    void do_foo(T t) { 
    foo(t); 
    } 
} 

namespace B{ 
    struct bar {}; 
} 

void foo(B::bar) { 
    std::cout << "foobar!\n"; 
} 

do_foo::fooのdefinitonで見えなかった、そしてそれはB::barに関連付けられた名前空間に存在しないように、それはADLを介して検出されませんようにまた、同じmainで構築しません。

fooを​​に移動すると、両方のケースが機能します。

operator>>は、基本的に同じ規則に従います。

+1

'namespace boost'にゼロ演算子>>' sが含まれていても、テンプレート定義コンテキストだけを考慮するため、通常の非修飾ルックアップでは ':: operator >>'はまだ見つからないでしょう。 –

+0

@ t.c。ヘッダーをインクルードする前に ''を定義していれば、それが見つかります。 ;) – Yakk

関連する問題