C++ 完美转发仅复制类型到 make_tuple

C++ perfect forward copy-only types to make_tuple

我正在玩这个小片段:

#include <tuple>

struct copy_only
{
    copy_only() = default;
    copy_only(copy_only&&) = delete;
    copy_only(const copy_only&) = default;
};

template <typename ...Ts>
void foo(Ts&& ...xs)
{
    auto t = std::make_tuple(std::forward<Ts>(xs)...);
    (void) t;
}

int main()
{
   foo(copy_only{});
}

它与 gcc7 和 clang3.6、clang3.7、clang3.8 (Wandbox) 和 clang8.0 (macOS Sierra) 编译良好。它不使用 clang3.9、g++6.2 (macOS Sierra) 或 clang4.0 (Wandbox) 进行编译。他们都抱怨删除了移动构造函数。

它适用于仅移动类型。至少在 Wandbox 上可用的上述编译器上。

此代码是在 C++14 中将通用完美转发到元组的正确方法的示例吗?

    auto t = std::make_tuple(std::forward<Ts>(xs)...);

这确实是将参数转发到元组中的正确方法。

您得到的编译错误是由于显式声明 copy_only 的移动构造函数已删除引起的。通常,如果您声明了一个复制构造函数,它会被省略,并且在移动上下文中会选择复制构造函数——自 C++98 以来一直如此。但是因为您显式声明了它,所以它确实参与了重载决议并导致代码在选择时格式错误。

这是 Howard Hinannt 提供的有用图表:

这可以通过从 class 定义中删除有问题的行来解决:

struct copy_only
{
    copy_only() = default;
    //copy_only(copy_only&&) = delete;
    copy_only(const copy_only&) = default;
};

现在,关于您的代码是否应该编译:据我所知,应该。 tuple 的移动构造函数定义为:

tuple(tuple&& u) = default;

Requires: is_move_constructible<Ti>::value is true for all i.

由于 copy_only 不可移动构造,因此不应声明也不应参与重载决策。