std :: make_shared в качестве аргумента по умолчанию не компилируется - PullRequest
4 голосов
/ 07 мая 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»: не является членом «глобального пространства имен»

ошибка C3861: 'make_shared': идентификатор не найден

Он жалуется на определение P :: Foo (), а не :: Foo ().

Кто-нибудь знает, почему для Foo () допустимо иметь аргумент по умолчанию с std :: make_shared, но не P :: Foo ()?

Ответы [ 2 ]

6 голосов
/ 07 мая 2010

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

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 нет проблем с этим кодом.

0 голосов
/ 06 мая 2011

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

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

...