【问题标题】:Compilation error declaring a unique_ptr member in a class在类中声明 unique_ptr 成员的编译错误
【发布时间】:2021-04-21 11:01:09
【问题描述】:

这是某种工厂 lambda。由 lambda 实例化的类在其构造函数中接收对另一个类的引用。如果后者声明了一个 unique_ptr 成员,则会抛出一个很长的错误:

#include <memory>
#include <string>

struct A
{
    std::unique_ptr<int> foo;
};

struct B
{
    B(const std::string & str, A&a) {}
};

template<typename T, typename ... Args>
auto registerType(const std::string & type, Args&& ... args)
{

    return [args = std::make_tuple(std::forward<Args>(args) ...)]() mutable -> auto
    {
        return std::apply([](auto&& ... args){
            return std::make_unique<T>(args ...);
        }, std::move(args));
    };
}

int main()
{
    A a;
    registerType<B>("lala", "p1", a)();
}

删除 unique_ptr 成员可以正常工作。 传递指向“a”的指针而不是引用也可以正常工作。

错误输出很长,最好在实际中看到它:

https://godbolt.org/z/n896qMz59

这至少发生在:

  • g++ 9.2.0 和主干
  • clang++ 主干

有什么想法吗?

谢谢

【问题讨论】:

  • 错误是:no matching function for call to 'std::tuple&lt;const char*, A&gt;::tuple(const char [3], A&amp;)
  • registerType&lt;B&gt;("lala", "p1", std::move(a))(); godbolt.org/z/W88hTrT48

标签: c++ g++ c++17 clang++


【解决方案1】:

您不能复制unique_ptr

但你可以移动它:

#include <utility>

// ...

registerType<B>("lala", "p1", std::move(a))();

或防止在使用make_tuple 时出现std::decay

return [args = std::tuple<Args...>(std::forward<Args>(args) ...)]() mutable -> auto

【讨论】:

  • 你可以,但如果你这样做std::ref(a),仍然可以将其作为参考传递,但这无疑会导致其他问题
  • 啊...这么简单...好吧,我知道我不能不复制一个 unique_ptr,但是你能告诉我错误输出中充满元组错误的位置,至少有有什么线索吗?为什么要复制它?
  • @osovan std::make_tuple 衰减它的参数,删除引用并因此复制最初作为a 传入的struct A。见en.cppreference.com/w/cpp/utility/tuple/make_tuple
  • @osovan 对于不同的编译器,错误输出是不同的——没有一个是容易解析的。 :-) 是的,这是make_tuple 的衰变。我添加了一个选项来防止这种情况发生。
  • @TedLyngmo 感谢您添加选项。
猜你喜欢
  • 1970-01-01
  • 2017-03-31
  • 2022-11-14
  • 1970-01-01
  • 2015-01-18
  • 1970-01-01
  • 1970-01-01
  • 2013-12-09
  • 2012-04-03
相关资源
最近更新 更多