29

I need a type trait to check whether all types in a parameter pack are copy constructible. This is what I've done so far. The main function contains some test cases, to check the functionality.

#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

My idea was to check recursively, whether the head element of the pack is copy-constructible or not and go on further, with the tail. Unfortunately, I do not get this idea to compile. My knowledge about variadic templates is not very advanced. I guess, that enable-if after parameter pack in template list does not work. I have no idea. Does anyone has a good advice, how to solve the problem?

meddle0106
  • 1,292
  • 1
  • 11
  • 22

4 Answers4

34

First define a reusable utility to test whether every predicate in a pack is true:

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
  { };

Then it's trivial to use that with is_copy_constructible (or any other unary type trait):

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

One advantage of defining and_ like this is that it short-circuits, i.e. stops instantiating is_copy_constructible for the rest of the pack after the first false result.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
11

I prefer @Columbo's bool_pack trick. First a template to test that everything in a bool parameter pack is true:

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

Then

template<class... Ts>
using areCopyConstructible = all_true<std::is_copy_constructible<Ts>::value...>;
T.C.
  • 133,968
  • 17
  • 288
  • 421
  • 1
    This is very clear and simple, but does eager evaluation of all the `is_copy_constructible` specializations. A slightly more complicated solution only evaluates as many as necessary to find the answer, i.e. it short circuits. – Jonathan Wakely Apr 13 '15 at 11:14
  • 3
    @JonathanWakely I still believe this is more efficient overall - recursion with packs is quite inefficient IIRC. Fortunately this debate will be over in C++1Z with fold expressions. – Columbo Apr 13 '15 at 11:43
  • @Columbo, yes, good point about fold expressions. `is_copy_constructible::value` might have to instantiate a lot of code, including base classes and members of `T`, to determine if a type has an accessible copy constructor, so avoiding that might be good (although it will depend on the types). My `and_` type is very simple, even though it uses recursion. – Jonathan Wakely Apr 13 '15 at 13:51
  • 3
    @JonathanWakely I think the most common use case for this trait would be to verify that a pack of types are all copy constructible in a `static_assert`, so it would usually be instantiated with all-copy-constructible types, and the difference between eager and lazy disappears. – T.C. Apr 13 '15 at 17:34
  • @T.C. good point. We use something like `and_` throughout libstdc++ for much more general use cases, and in SFINAE constraints where it is not expected that everything will be true, but for the OP's situation short-circuiting probably doesn't offer any benefit. – Jonathan Wakely Apr 13 '15 at 18:00
10

If the inheritance from std::true_type or std::false_type is not important, then this can be done in straightforward way without 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;
};

If you want to inherit from std::true_type or std::false_type, you can use 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
{};
Anton Savin
  • 40,838
  • 8
  • 54
  • 90
  • 1
    What's worth mentioning is that unlike the OP, you don't bother deriving from `false_type` or from `true_type` except in the trivial case. The user probably won't need that, but I have seen code here on SO that uses `false_type` and `true_type` in overloaded function parameters, so things like that won't work. It's easy enough to add, if it's wanted, though. –  Apr 13 '15 at 10:55
5

I know that it is an old question but as we will have C++17 soon, I encourage to take a look at std::conjunction. With it you could write something like this

template <typename ...Args>
using areCopyConstructible = typename std::conjunction<std::is_copy_constructible<Args>...>::type;
stryku
  • 722
  • 5
  • 12
  • N.B. yep, `std::conjunction` is based on the `and_` template I showed in my answer. – Jonathan Wakely Sep 26 '16 at 11:34
  • N.B. Instead of using `bool_constant>` you can just use `conjunction<...>::type` which is already a `bool_constant`, or even simpler `conjunction<...>` (which is something derived from a `bool_constant`). – Jonathan Wakely Sep 26 '16 at 11:34
  • N.B. using an alias template instead of defining a new class template has less overhead at compile-time. – Jonathan Wakely Sep 26 '16 at 11:37
  • I posted pretty much the same thing a couple of hours ago, so once I realized it I deleted my answer and linked to this one from [here](https://ngathanasiou.wordpress.com/2016/12/18/quantifiers-metaprogramming-and-concepts/) – Nikos Athanasiou Dec 19 '16 at 09:22