std::make_shared в качестве аргумента по умолчанию не компилируется

В 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()?


person Mark Bryant    schedule 07.05.2010    source источник
comment
Обратите внимание, что в Visual C++ 2008 shared_ptr находится в std::tr1, а make_shared не реализовано (make_shared не было частью TR1).   -  person James McNellis    schedule 07.05.2010
comment
похоже на то, что ты делаешь ::make_shared   -  person Johannes Schaub - litb    schedule 07.05.2010
comment
Не обращайте внимания на бит 2008 года, я путаю IDE с компилятором.   -  person Mark Bryant    schedule 07.05.2010
comment
Я могу воспроизвести проблему в VS2010. Я переключил его на использование boost::shared_ptr, и он не будет компилироваться в VS2008. Он жалуется, что не может вывести аргумент шаблона для «T», что для меня не имеет никакого смысла, потому что вы явно указываете T (int).   -  person James McNellis    schedule 07.05.2010


Ответы (2)


Похоже на ошибку в компиляторе. Вот минимальный код, необходимый для воспроизведения проблемы:

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'

У Комо нет проблем с этим кодом.

person James McNellis    schedule 07.05.2010
comment
Я отправил отчет о дефекте в Microsoft Connect: connect.microsoft.com/VisualStudio/feedback/details /557653 - person James McNellis; 07.05.2010

Я столкнулся с той же проблемой в моем собственном коде. Минимальный код, к которому я его сводил, был таким:

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

Это немного отличается от примера Джеймса Макнеллиса - и, я думаю, подчеркивает тот факт, что это квалификация пространства имен в инициализаторе аргумента по умолчанию, где что-то идет не так.

В этом случае defaultValue и fun находятся в одном и том же пространстве имен, поэтому вы можете тривиально удалить N:: из N::defaultValue, и это сработает.

Если 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, хотя я не пробовал.

person philsquared    schedule 06.05.2011