4

Visual C++ (2008 および 2010) では、次のコードは次のエラーでコンパイルされません。

#include <memory>

void Foo( std::shared_ptr< int >    test = ::std::make_shared< int >( 5 ) )
{
}

class P
{
    void
    Foo( std::shared_ptr< int > test = ::std::make_shared< int >( 5 ) )
    {
    }
};

エラー C2039: 'make_shared' : '`グローバル名前空間'' のメンバーではありません

エラー C3861: 'make_shared': 識別子が見つかりません

::Foo() ではなく P::Foo() の定義について不平を言っています。

P::Foo() ではなく std::make_shared でデフォルト引数を持つことが Foo() にとって有効である理由を誰かが知っていますか?

4

2 に答える 2

6

コンパイラのバグのようです。問題を再現するために必要な最小限のコードは次のとおりです。

namespace ns
{
    template <typename T>
    class test
    {
    };

    template <typename T>
    test<T> func()
    {
        return test<T>();
    }
}

// Works:
void f(ns::test<int> = ns::func<int>()) { }

class test2
{
    // Doesn't work:
    void g(ns::test<int> = ns::func<int>()) 
    { 
    }
};

Visual C++ 2008 と 2010 の両方で次のように報告されます。

エラー C2783: ' ': ' 'ns::test<T> ns::func(void)のテンプレート引数を推定できませんでしたT

Comeau はこのコードに問題はありません。

于 2010-05-07T14:16:31.067 に答える
0

自分のコードで同じ問題のように見えるものを見つけました。煮詰めた最小限のコードは次のとおりです。

namespace N
{
    template<typename T>
    T defaultValue()
    {
        return T();
    }

    template<typename T>
    void fun( const T& value = N::defaultValue<T>() ){}
}

int main(int argc, char* argv[])
{
    N::fun<int>();
    return 0;
}

これは、James McNellis の例とは少し異なります。そして、デフォルトの引数初期化子の名前空間の修飾が間違っているという事実を浮き彫りにしていると思います。

この場合、defaultValue と fun は同じ名前空間にあるため、N::defaultValue から N:: を簡単に削除すると機能します。

defaultValue が別の名前空間にある場合でも、使用してローカル名前空間に持ち込むか、ローカル転送テンプレート関数を記述することで回避できます。たとえば、次のようになります。

namespace N1
{
    template<typename T>
    T defaultValue()
    {
        return T();
    }
}
namespace N2
{
    template<typename T>
    T defaultValueFwd()
    {
        return N1::defaultValue<T>();
    }

    template<typename T>
    void fun( const T& value = defaultValueFwd<T>() ){}
}

int main(int argc, char* argv[])
{
    N2::fun<int>();
    return 0;
}

少し痛いですが、実行可能です。私は試したことはありませんが、make_shared の場合にこの手法を使用できると思います。

于 2011-05-06T11:11:34.690 に答える