문제

In Visual C++ (2008 and 2010), the following code does not compile with the following error:

#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 ) )
    {
    }
};

error C2039: 'make_shared' : is not a member of '`global namespace''

error C3861: 'make_shared': identifier not found

It is complaining about the definition of P::Foo() not ::Foo().

Does anybody know why it is valid for Foo() to have a default argument with std::make_shared but not P::Foo()?

도움이 되었습니까?

해결책

It looks like a bug in the compiler. Here is the minimal code required to reproduce the problem:

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 and 2010 both report:

error C2783: 'ns::test<T> ns::func(void)' : could not deduce template argument for 'T'

Comeau has no issues with this code.

다른 팁

I hit what appears to be the same issue in my own code. The minimal code I boiled it down to was this:

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;
}

This is slightly different to James McNellis example - and, I think, highlights the fact that it is the namespace qualification in the default argument initiliser where it goes wrong.

In this case defaultValue and fun are in the same namespace, so you can trivially remove N:: from N::defaultValue and it works.

If defaultValue is in a different namespace you can still workaround it by either bringing it into the local namespace with using, or writing a local forwarding template function, e.g.:

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;
}

A bit of a pain, but workable. I believe you could use this technique in the make_shared case, although I haven't tried it.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top