类型特征以检查参数包中的所有类型是否可复制构造

Type trait to check that all types in a parameter pack are copy constructible

我需要一个类型特征来检查参数包中的所有类型是否都是可复制构造的。这是我到目前为止所做的。主要功能包含一些测试用例,以检查功能。

#include <type_traits>
#include <string>
#include <memory> 

template <class... Args0toN>
struct areCopyConstructible;

template<>
struct areCopyConstructible<> : std::true_type {};

template <class Arg0, class... Args1toN, class std::enable_if< !std::is_copy_constructible<Arg0>::value>::type* = nullptr >
struct areCopyConstructible : std::false_type {};

template <class Arg0, class... Args1toN, class std::enable_if< std::is_copy_constructible<Arg0>::value>::type* = nullptr >
struct areCopyConstructible : areCopyConstructible<Args1toN...> {};

int main()
{
  static_assert(areCopyConstructible<>::value, "failed");
  static_assert(areCopyConstructible<int>::value, "failed");
  static_assert(areCopyConstructible<int, std::string>::value, "failed");
  static_assert(!areCopyConstructible<std::unique_ptr<int> >::value, "failed");
  static_assert(!areCopyConstructible<int, std::unique_ptr<int> >::value, "failed");
  static_assert(!areCopyConstructible<std::unique_ptr<int>, int >::value, "failed");
}

Link to Live Example

我的想法是递归地检查包的头部元素是否可复制构造,然后继续检查尾部。不幸的是,我没有编译这个想法。我对可变参数模板的了解不是很深。我猜,模板列表中参数包后的 enable-if 不起作用。我不知道。有没有人有好的建议,如何解决问题?

如果从 std::true_typestd::false_type 的继承不重要,那么这可以在没有 SFINAE 的情况下以直接的方式完成:

template <class... Args0toN>
struct areCopyConstructible;

template<>
struct areCopyConstructible<> : std::true_type {};

template <class Arg0, class... Args1toN>
struct areCopyConstructible<Arg0, Args1toN...> {
    static constexpr bool value = std::is_copy_constructible<Arg0>::value
        && areCopyConstructible<Args1toN...>::value;
};

如果想继承std::true_typestd::false_type,可以使用std::conditional:

template <class... Args0toN>
struct areCopyConstructible;

template<>
struct areCopyConstructible<> : std::true_type {};

template <class Arg0, class... Args1toN>
struct areCopyConstructible<Arg0, Args1toN...> : 
    std::conditional<std::is_copy_constructible<Arg0>::value,
        areCopyConstructible<Args1toN...>,
        std::false_type
    >::type
{};

首先定义一个可重用的实用程序来测试包中的每个谓词是否为真:

template<typename... Conds>
  struct and_
  : std::true_type
  { };

template<typename Cond, typename... Conds>
  struct and_<Cond, Conds...>
  : std::conditional<Cond::value, and_<Conds...>, std::false_type>::type
  { };

然后将它与 is_copy_constructible(或任何其他一元类型特征)一起使用是微不足道的:

template<typename... T>
  using areCopyConstructible = and_<std::is_copy_constructible<T>...>;

像这样定义 and_ 的一个优点是它会短路,即在第一个错误结果后停止为包的其余部分实例化 is_copy_constructible

我更喜欢@Columbo 的bool_pack 把戏。首先是一个模板,用于测试 bool 参数包中的所有内容是否为 true:

template<bool...> struct bool_pack;
template<bool... bs> 
using all_true = std::is_same<bool_pack<bs..., true>, bool_pack<true, bs...>>;

然后

template<class... Ts>
using areCopyConstructible = all_true<std::is_copy_constructible<Ts>::value...>;

我知道这是一个老问题,但由于我们很快就会有 C++17,我鼓励看一下 std::conjunction。有了它你可以写这样的东西

template <typename ...Args>
using areCopyConstructible = typename std::conjunction<std::is_copy_constructible<Args>...>::type;