键入trait以检查参数包中的所有类型是否可复制构造

med*_*106 28 c++ templates type-traits c++11

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

#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");
}
Run Code Online (Sandbox Code Playgroud)

链接到实例

我的想法是递归检查,包的头部元素是否是可复制构造的,并继续进行尾部.不幸的是,我没有这个想法来编译.我对可变参数模板的了解不是很先进.我想,启用 - 如果在模板列表中的参数包之后不起作用.我不知道.有没有人有好的建议,如何解决问题?

Jon*_*ely 32

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

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
  { };
Run Code Online (Sandbox Code Playgroud)

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

template<typename... T>
  using areCopyConstructible = and_<std::is_copy_constructible<T>...>;
Run Code Online (Sandbox Code Playgroud)

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

  • 很优雅的解决方案 C++ 14`std :: conditional_t`可以保存输入`:: type`. (3认同)

T.C*_*.C. 10

我更喜欢@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...>>;
Run Code Online (Sandbox Code Playgroud)

然后

template<class... Ts>
using areCopyConstructible = all_true<std::is_copy_constructible<Ts>::value...>;
Run Code Online (Sandbox Code Playgroud)

  • @JonathanWakely我仍然认为整体效率更高 - 包装的递归效率非常低IIRC.幸运的是,这个辩论将在带有折叠表达式的C++ 1Z中结束. (3认同)
  • @JonathanWakely我认为这个特性最常见的用例是验证一组类型是否都可以在`static_assert`中进行复制构造,因此通常会使用all-copy-constructible类型进行实例化,并且eager之间存在差异和懒惰消失. (3认同)

Ant*_*vin 9

如果继承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;
};
Run Code Online (Sandbox Code Playgroud)

如果您想继承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
{};
Run Code Online (Sandbox Code Playgroud)


str*_*yku 5

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

template <typename ...Args>
using areCopyConstructible = typename std::conjunction<std::is_copy_constructible<Args>...>::type;
Run Code Online (Sandbox Code Playgroud)