Вычисление шаблона не удалось из кучи, но работает в стеке
У меня проблема с шаблоном. Когда я создаю экземпляр класса в стеке, он работает. Когда я создаю экземпляр одного класса в куче, он терпит неудачу. (аргумент дедукции) Я не понимаю, почему...
Информация: Я использую gcc 7.2.0 с С++ 17.
вот пример:
#include <iostream>
#include <cstdlib>
#include <memory>
template <class ReturnType, class ClassName, class... Args>
class MethodPtr
{
public:
typedef ReturnType (ClassName::*Method)(Args...);
MethodPtr(ClassName* ptr, Method m) : _p(ptr), _m(m)
{
(ptr->*m)(4);
}
ClassName* _p;
Method _m;
};
class Example
{
public:
Example()
{
dotest(this, &Example::func);
}
template <class Ptr, class Func>
void dotest(Ptr ptr, Func func)
{
// works
MethodPtr(ptr, func);
// don't works
//std::make_unique<MethodPtr>(ptr, func);
//new MethodPtr(ptr, func);
//works
std::make_unique<decltype(MethodPtr(ptr, func))>(ptr, func);
new decltype(MethodPtr(ptr, func))(ptr, func);
}
void func(int i)
{
std::cout << i << std::endl;
}
};
int main()
{
Example example;
}
У вас есть решение избежать decltype?
Спасибо,
Ответы
Ответ 1
Тот факт, что new MethodPtr(ptr, func)
не позволяет сделать вывод, является ошибкой компилятора. Согласно [dcl.type.class.deduct]/2:
Заполнитель для выведенного типа класса также может использоваться в типе-спецификаторе-seq в идентификаторе нового типа или типе-идентификатора нового выражения или в качестве спецификатора простого типа при явном преобразовании типа (функциональный нотация) ([expr.type.conv]). Заполнитель для выведенного типа класса не должен появляться ни в каком другом контексте.
Как вы можете видеть, явное да для нового выражения и полный запрет на все, что явно не разрешено. Поэтому make_unique
не может быть присвоен.
Если вы не можете перейти на версию GCC, где это исправлено (или вам просто нужно использовать make_unique
), вы не можете избежать decltype
. Попробуйте ввести псевдоним типа, чтобы уменьшить неудобства.
Ответ 2
В последних gcc и clang это работает - это new MethodPtr(ptr, func)
. Так что для gcc7.2 - это ошибка.
Для unique_ptr(new MethodPtr(ptr, func))
- он не может работать, потому что в C++ - на этом уровне, имея MethodPtr*
- мы не можем различать unique_ptr<MethodPtr[]>
и unique_ptr<MethodPtr>
- поэтому он не может быть выводится.
Ответ 3
Посмотрите здесь. Передача просто MethodPtr
(шаблон класса) как параметра типа шаблона шаблона функции (std::make_unique
) никогда не разрешалась, а вывод шаблона шаблона класса не менял этого.
new MethodPtr{ptr, func};
работает, глядя на ссылку, но я не могу сказать, почему это должно быть иначе, чем new MethodPtr(ptr, func);