11

Why does the following code compile?

#include <memory>
#include <vector>

int main()
{
    std::vector<std::unique_ptr<int>> uncopyableStuff;
    for(int i = 0; i < 5; ++i)
        uncopyableStuff.emplace_back(std::make_unique<int>(i));
    auto lambda = [uncopyableStuff = std::move(uncopyableStuff)](){};
    static_assert(std::is_copy_constructible<decltype(lambda)>::value);
}

It seems to me that lambda is uncopyable, because when I try to copy it like:

auto copy = lambda;

This gives me a compile error (as I would expect). Is there some exception for lambda's and copy constructability traits?

See link for godbolt example: https://godbolt.org/z/GByclH

EDIT:

What is the correct way to find out whether a lambda will compile when attempted to copy. I geuss I'm not interested in the theoretical copy constructibility of a given callable, but a detection of successful copy construction. It still seems very strange to me that the vector copy constructor is defined in this way.

Andreas Loanjoe
  • 2,205
  • 10
  • 26
  • 2
    `std::is_copy_constructible::value` is true because `std::vector>` has a non-deleted copy constructor. The body of that constructor is of course ill-formed (since it calls the copy constructor of `std::unique_ptr`), but that's outside the immediate context, so it cannot be detected by the type trait. – cpplearner Apr 12 '19 at 16:59
  • 4
    Possible duplicate of [Issue with is\_copy\_constructible](https://stackoverflow.com/questions/18404108/issue-with-is-copy-constructible) – cpplearner Apr 12 '19 at 17:00
  • Re “EDIT”: there is no way in general to find out if something will compile; the compilers do not (yet?) have any means of “recovering” from arbitrary errors and resuming from your desired test with `false`. – Davis Herring Apr 12 '19 at 17:28

1 Answers1

7

Is there some exception for lambda's and copy constructability traits?

No. If you test std::is_copy_constructible<std::vector<std::unique_ptr<int>>>::value you will find that it's also true.

The reason is that std::vector has an accessible and non-deleted copy constructor even if the element type is noncopyable. If the copy constructor is instantiated, it will fail to compile, but that's outside the immediate context, and thus cannot be detected by the std::is_copy_constructible trait.

It might be tempting to make the copy constructor of std::vector SFINAE on the copy constructibility of the element type, but I believe it will break a type that stores a vector of the type itself as a member: struct Node { std::vector<Node> children; }, since in this case, the copy constructibility of Node and std::vector<Node> would be mutual dependent.

cpplearner
  • 13,776
  • 2
  • 47
  • 72
  • That's an interesting question. SFINAE cannot be used on self-references like this. Can concepts do it, since it's kind of a legit language version of SFINAE? – Nicol Bolas Apr 12 '19 at 17:38