Почему нельзя использовать auto в качестве параметра типа шаблона? - PullRequest
10 голосов
/ 28 июля 2011

Я играл с ключевым словом C ++ 0x auto и попробовал следующее.

std::unique_ptr<auto> ptr(new int(0));

Я попытался скомпилировать его с помощью g ++ 4.4.5 и получил

error: invalid use of auto

Судя по глазу, auto можно легко вывести на int.

Я предполагаю, что вывод типа и механизм шаблонов не общаются друг с другом.В противном случае, шаблонизатор будет знать, когда создать экземпляр класса шаблона с int в качестве параметра типа.

Другое предположение из стандарта, я вижу это.

A member shall not be declared with auto, extern or register storage class.

Но я подумалэто был auto как в локальных переменных, а не как auto, используемый для вывода типов.

И мое последнее предположение, что компилятор думает, что это auto класс хранения, а не autoдля вычета типа.

Существует ли причина, заявленная в стандарте?

Ответы [ 4 ]

10 голосов
/ 28 июля 2011

Это потому, что он должен определить класс для вызова конструктора до , определяющего, что делать с его аргументами. Если вы сделаете конструктор шаблоном, он просто будет работать как любая другая функция шаблона - автоматически определяемые аргументы.

5 голосов
/ 28 июля 2011

@ dascandy правильно определил, что не так с вашим кодом.Я попытаюсь дать некоторые объяснения:

Вы ожидаете, что компилятор выведет unique_ptr<int>, потому что аргумент - int*, а unique_ptr<int> имеет конструктор, который принимает int*.На мгновение давайте проигнорируем тот факт, что мы используем std::unique_ptr, и просто поговорим о классе шаблона, который мы написали (и можем специализировать).

Почему компилятор должен выводить unique_ptr<int>?Аргумент не int, это int*.Почему бы не угадать unique_ptr<int*>?Конечно, это приведет к ошибке компилятора, так как конструктор unique_ptr<int*> не примет int*.Если я не добавлю специализацию:

template<>
class unique_ptr<int*>
{
public:
    unique_ptr(int*) {}
};

Теперь unique_ptr<int*> будет компилироваться.Откуда компилятору знать, какой выбрать, unique_ptr<int> или unique_ptr<int*>?Что, если я добавлю еще одну специализацию?

template<>
class unique_ptr<double>
{
public:
    unique_ptr(int*) {}
};

Теперь у компилятора есть три варианта выбора, и он должен создать экземпляр шаблона со всеми возможными аргументами, чтобы найти их.Ясно, что это невозможно, особенно с несколькими аргументами шаблона и рекурсией шаблона.

Что вы можете сделать, это создать фабричную функцию, которая связывает выведенный тип с одним экземпляром шаблона:

template<typename T>
std::unique_ptr<T> make_unique(T* arg) { return arg; }

(конечно, это не сработает, потому что unique_ptr невозможно скопировать. Но идея верна и используется, например, в make_shared и make_pair.)


Некоторые примеры экстремальныхуродство:

Можно утверждать, что unique_ptr<shared_ptr<int>> является допустимым соответствием для этого кода.

Или как насчет:

template<typename T>
class unique_ptr
{
public:
    explicit unique_ptr(T* arg);
    unique_ptr(int*, enable_if<(sizeof(T) > 16)>::type* = 0);
};
2 голосов
/ 28 июля 2011

Это (или подобное) было предложено для Стандарта. Предложенный функционал выглядел примерно так:

std::vector<int> GetMahVector();
std::vector<auto> var = GetMahVector();

Однако оно было отклонено. Почему это было отклонено, ну, если возможно, вам придется выкопать соответствующие стандартные документы процесса.

2 голосов
/ 28 июля 2011

Просто хочу добавить, что решение для большинства случаев уже существует:

template <typename T>
std::unique_ptr<T> unique_ptr_auto(T* ptr)
{
    // fails to handle std::unique_ptr<T[]>, not deducible from pointer
    return std::unique_ptr<T>(ptr);
}

auto ptr = unique_ptr_auto(new int(0));

Немного более многословно, очевидно, но вы поняли идею.Эти «функции генератора» довольно распространены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...