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”:找不到标识符

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

有谁知道为什么 Foo() 使用 std::make_shared 而不是 P::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 回答