unique_ptr <T>成员的模板化通用setter

ser*_*ean 2 c++ c++17

我正在尝试创建一个通用的setter,支持值和指针.我的指针有问题.说明主要想法的最小代码:

#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);
}
Run Code Online (Sandbox Code Playgroud)

编译(gcc-7.3.0)失败了

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

我没有关于如何获得指针类型的想法......另外,引用来自哪里?(更改ptr参数无法解决)

Bar*_*rry 6

你刚才有一个错字:

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

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);
}
Run Code Online (Sandbox Code Playgroud)

通过直接使用名称,您可以更简单地编写p:

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

但这可能实际上并不正确,因为它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);
}
Run Code Online (Sandbox Code Playgroud)

现在,这段代码真的只适用于原始指针(你必须使用movea unique_ptr并且你不能将a转换shared_ptr为a unique_ptr),所以你可以更清楚地表达在函数签名中,这也使得身体更容易编写:

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

这最终引出了为什么要写的问题:

set(dd, new A);
Run Code Online (Sandbox Code Playgroud)

代替:

dd = std::make_unique<A>();
Run Code Online (Sandbox Code Playgroud)

无论如何?第二是远远优越.