开发者

std::make_shared as a default argument does not compile

开发者 https://www.devze.com 2022-12-29 06:30 出处:网络
In Visual C++ (2008 and 2010), the following code does not compile with the following error: #include <memory>

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消