2017-09-14 101 views
2
#include <memory> 

template <typename T> 
class Wrapper { 
public: 
    Wrapper() = delete; 
    Wrapper(const Wrapper&) = delete; 
    Wrapper(Wrapper&&) = delete; 

    ~Wrapper() = default; 

    Wrapper(const T&) = delete; 
    Wrapper(T&& in) : instance{std::move(in)} {} 

    T instance; 
}; 

void foo(Wrapper<std::shared_ptr<int>>) {} 

int main() { 
    auto ptr = std::make_shared<int>(1); 
    foo(std::move(ptr)); 
} 

这一直致力于在C++ 17所以我从来没有给它认为,但为什么会发生这种代码尝试和调用在C++ 14的移动构造函数?它不应该在函数参数中构建吗?这看起来不是C++ 17的问题,但不是用C++ 14编译的。复制参数调用构造函数删除时构造不应该叫

我看到的唯一解决方法是使foo参数为右值,但是有什么我可以做的,使得这项工作不需要在foo中使参数在C++ 14中成为一个右值?


我首先想到的会是暂时的必须是构造函数才能被传递给函数,但什么是更令人惊讶的是,即使-fno-elide-constructors和取消删除移动构造函数和拷贝构造函数那些不似乎被称为!这是gcc和clang中的一个bug吗?

的错误 见https://wandbox.org/permlink/f6sa5Rm3NxZLy5P1,看看奇怪的行为https://wandbox.org/permlink/Kh6CG4OVbUAjvEZz

+1

什么是确切的错误,你会得到 – vu1p3n0x

+0

@ vu1p3n0x张贴他们的问题,它是在标题以及 – Curious

+1

在你的链接,“看到了奇怪的行为,”它确实呼叫转移构造 –

回答

4

当你调用foo(std::move(ptr));你不给它一个Wrapper<std::shared_ptr<int>>。因此,编译器会生成一个临时文件并使用它来构造foo的参数。现在,这可以被忽略,我们可以直接构造一个Wrapper<std::shared_ptr<int>>,但移动/复制构造函数仍然需要可访问,即使它从不被调用。

随着C++ 17的不再发生。我们有guaranteed copy elision这意味着没有临时实现,而是直接构造参数。

+0

但为什么移动构造函数从来没有调用?即使使用'-fno-elide-constructors' – Curious

+0

@语言所需的复杂构造函数,但可以通过优化来消除调用。 – Slava

+0

@Curious因为即使编译器足够聪明以至于暂时不符合语言标准,仍然可以访问相应的构造函数。 – NathanOliver