шаблонный универсальный сеттер для элемента unique_ptr <T> - PullRequest
0 голосов
/ 29 сентября 2018

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

#include <memory>
#include <variant>

class A{
    int s;
};

template <typename uniq, typename ptr>
void set(uniq &u, const ptr &p){
    u = std::unique_ptr<decltype(*std::declval<ptr>)>(p);
}

int main(){
    std::variant<std::unique_ptr<A>> dd;
    set(dd, new A);
}

Компиляция (gcc-7.3.0) завершается неудачно с

no matching function for call to ‘std::unique_ptr<A*&& (&)() noexcept, std::default_delete<A*&& (&)() noexcept> >::unique_ptr(A* const&)’

У меня нет идей о том, как получить тип указателя... Кроме того, откуда эта ссылка?(изменение параметра ptr не решает проблему)

Ответы [ 4 ]

0 голосов
/ 29 сентября 2018

Реализация немного странная.если вы знаете, что собираетесь установить unique_ptr на u, то почему templatize имеет значение uniq, а не std::unique_ptr<type>?

Учитывая то, что я написал выше, я бы реализовал это как

template <class type>
void set(std::unique_ptr<type>& unique_pointer, type* pointer) {
    unique_pointer.reset(pointer);
}

template <class type, class ... argument_types>
void set(std::unique_ptr<type>& unique_pointer, argument_types&& ... args) {
    unique_pointer = std::make_unique<type>(std::forward<argument_types>(args)...);
}

int main() {
    std::unique_ptr<std::string> up0, up1, up2, up3;

    set(up0);
    set(up1, "hello world");
    set(up2, "   hello world   ", 3, 11);
    set(up3, new std::string("hello world"));
    return 0;
}
0 голосов
/ 29 сентября 2018

Вы можете использовать std::unique_ptr<>::reset:

std::variant<std::unique_ptr<A>> u;
A* p = new A;
std::get<0>(u).reset(p);

Или:

using unique_ptr_type = typename std::decay<decltype(std::get<0>(u))>::type;
u = unique_ptr_type(p);
0 голосов
/ 29 сентября 2018

У вас просто есть опечатка:

template <typename uniq, typename ptr>
void set(uniq &u, const ptr &p){
    u = std::unique_ptr<decltype(*std::declval<ptr>)>(p);
    //                                            ^^^
}

std::declval - это функция, поэтому код, который вы пишете, пытается разыменовать этот тип функции.Что является действительным, что нужно сделать!Вот как вы получаете A*&& (&)() noexcept

То, что вы хотите:

template <typename uniq, typename ptr>
void set(uniq &u, const ptr &p){
    u = std::unique_ptr<decltype(*std::declval<ptr>())>(p);
}

Что вы можете написать намного проще, просто используя имя p:

template <typename uniq, typename ptr>
void set(uniq &u, const ptr &p){
    u = std::unique_ptr<decltype(*p)>(p);
}

Но это, вероятно, не совсем правильно, поскольку decltype(*p) обычно имеет ссылочный тип, и вы должны удалить его:

template <typename uniq, typename ptr>
void set(uniq &u, const ptr &p){
    u = std::unique_ptr<std::remove_reference_t<decltype(*p)>>(p);
}

Теперь этот код на самом деле * только 1020 *работает с необработанным указателем (вам нужно move a unique_ptr и вы не можете преобразовать shared_ptr в unique_ptr), чтобы вы могли более четко выразить это в сигнатуре функции, которая также делаеткузов гораздо проще написать:

template <typename uniq, typename T>
void set(uniq &u, T* p){
    u = std::unique_ptr<T>(p);
}

Что в конечном итоге вызывает вопрос, почему вы хотели бы написать:

set(dd, new A);

вместо:

dd = std::make_unique<A>();

в любом случае?2-й намного выше.

0 голосов
/ 29 сентября 2018

Для построения std::unique_ptr явно:

template <typename uniq, typename ptr>
void set(uniq &u, const ptr &p)
{
    using T = std::remove_pointer_t<ptr>;
    u = std::unique_ptr<T>(p);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...