26

次のC++プログラムについて考えてみます。

#include <memory>

struct A {};

struct B : A {};

int main()
{
    auto x = std::make_shared<A>();
    if (auto p = dynamic_pointer_cast<B>(x));
}

MSVC 2010でコンパイルすると、次のエラーが発生します。

error C2065: 'dynamic_pointer_cast' : undeclared identifier

autoに置き換えてもエラーは解決しませんstd::shared_ptr<A>。呼び出しを完全に修飾するとstd::dynamic_pointer_cast、プログラムは正常にコンパイルされます。

また、gcc4.5.1もそれを好きではありません:

error: 'dynamic_pointer_cast' was not declared in this scope

名前空間に存在するタイプなので、これはKoenigルックアップstd::dynamic_pointer_castによって選択されたと思います。ここで何が欠けていますか?xstd

4

2 に答える 2

24

セクション§14.8.1/6(C ++ 03、およびC ++ 11にも当てはまると思います)は、次のように読み取るこのケースに適用されると思います。

[注:単純な関数名の場合、関数名が呼び出しのスコープ内に表示されていない場合でも、引数依存のルックアップ(3.4.2)が適用されます。これは、呼び出しがまだ関数呼び出し(3.4.1)の構文形式を持っているためです。ただし、明示的なテンプレート引数を持つ関数テンプレートが使用されている場合、呼び出しのポイントにその名前の関数テンプレートが表示されていない限り、呼び出しには正しい構文形式がありません。そのような名前が表示されない場合、呼び出しは構文的に整形式ではなく、引数に依存するルックアップは適用されません。そのような名前が表示されている場合は、引数依存のルックアップが適用され、他の名前空間に追加の関数テンプレートが見つかる場合があります。

[例:

namespace A {
     struct B { };
     template<int X> void f(B);
}
namespace C {
     template<class T> void f(T t);
}
void g(A::B b) {
     f<3>(b);    //ill-formed: not a function call
     A::f<3>(b); //well-formed
     C::f<3>(b); //ill-formed; argument dependent lookup
                 // applies only to unqualified names

    using C::f;
     f<3>(b); //well-formed because C::f is visible; then
              // A::f is found by argument dependent lookup
}

—end example] —end note]

テンプレート引数を明示的に渡し、呼び出したサイトに同じ名前のテンプレートがないため、ケースはADLをトリガーしませんdynamic_pointer_cast

ADLを有効にするための1つのトリックは、以下に示すように、同じ名前のダミーテンプレートをコードに追加することです。

#include <memory>

struct A {};

struct B : A {};

template<int> //template parameter could be anything!
void dynamic_pointer_cast(); //ADD this. NO NEED TO DEFINE IT

int main()
{
   auto x = std::make_shared<A>();
   if (auto p = dynamic_pointer_cast<B>(x)); //now it should work through ADL
}
于 2012-03-23T12:07:30.613 に答える
18

Koenigルックアップは、関数の検索にのみ適用されます。ここでは、関数を作成する前に、まずテンプレートを見つけてからインスタンス化する必要があります。コードを単純に解析するために、コンパイラはdynamic_pointer_castそれがテンプレートであることを認識している必要があります(そうでない場合、「<」はテンプレート引数リストの先頭ではなく、より小さいです)。コンパイラがそれdynamic_pointer_castが関数テンプレートであることを知るまで、関数呼び出しが含まれていることさえ知りません。表示される式は基本的にですa < b > c。ここで、<および>は関係演算子です。

于 2012-03-23T12:08:24.253 に答える