std :: make_shared作为默认参数不编译

时间:2010-05-07 13:14:53

标签: c++ visual-c++ templates visual-c++-2008 visual-c++-2010

在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':不是'`global namespace''的成员

错误C3861:'make_shared':找不到标识符

抱怨P :: Foo()的定义不是:: Foo()。

有人知道为什么Foo()有一个与std :: make_shared但不是P :: Foo()的默认参数有效吗?

2 个答案:

答案 0 :(得分: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对此代码没有任何问题。

答案 1 :(得分: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的例子略有不同 - 而且,我认为,这突出了它是默认参数initiliser中的命名空间限定这一事实,它出错了。

在这种情况下,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的情况下使用这种技术,虽然我没有尝试过。