Variadic version of std::is_convertible?

痴心易碎 提交于 2019-12-09 15:59:30

问题


Is it possible to write a variadic version of std::is_convertible? For example are_convertible<T1, T2, T3, T4> would return is_convertible<T1, T3> && is_convertible<T2, T4>. I've been thinking about this for a few hours but couldn't come up with anything reasonable.

To clarify I want to use it somewhat like this:

template <class ...Args1>
struct thing
{
  template <class ...Args2>
  enable_if_t<are_convertible<Args2..., Args1...>::value>
  foo(Args2 &&...args){}
}

回答1:


You don't need to concatenate Args2... and Args1..., and you shouldn't, since doing to makes it makes it impossible to tell where Args2... ends and Args1... begins. The way to pass multiple variadic arguments in a way that allows them to be extracted individually is wrapping them in yet another template: given a variadic template my_list, you could structure your my_convertible to be called as

my_convertible<my_list<Args2...>, my_list<Args1...>>

The standard library already has a variadic template that works well here: tuple. Not only that, but tuple<Args2...> is convertible to tuple<Args1...> if and only if Args2... are convertible to Args1..., so you can just write:

std::is_convertible<std::tuple<Args2...>, std::tuple<Args1...>>

Note: in the comments, @zatm8 reports that this doesn't always work: std::is_convertible<std::tuple<const char *&&>, std::tuple<std::string &&>>::value is reported as false, but std::is_convertible<const char *&&, std::string &&>::value is reported as true.

I believe that this is a bug, that they should both be reported as true. The problem is reproducible on http://gcc.godbolt.org/ with clang 3.9.1. It is not reproducible with gcc 6.3, and it is also not reproducible with clang 3.9.1 when using -stdlib=libc++. It appears that libstdc++ is using a language feature that clang doesn't quite handle correctly, and reducing it to a short example that does not rely on standard library headers gives:

struct S {
  S(const char *) { }
};
int main() {
  const char *s = "";
  static_cast<S &&>(s);
}

This is accepted by gcc, but rejected by clang. It has been reported in 2014 as https://llvm.org/bugs/show_bug.cgi?id=19917.

It appears that this has been fixed in late 2016, but the fix has not yet made it into a released version: http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20161031/175955.html

If you are affected by this, you may wish to avoid std::tuple and use @Yakk's answer instead.




回答2:


Yes.

First, how to do it. Then, why you shouldn't do it.

How to do it:

Write regroup, that takes a list of kN elements and groups it into N groups of k, interleaved. Groups can be template<class...>struct types{};.

Then write apply, that takes a template<class...>class Z and a class... of groups (aka types<...>), and applies Z to the contents of each of the bundles, returning a types<...> of the result.

Then fold over the contents of types<...> using template<class A, class B> struct and_types:std::integral_constant<bool, A{}&&B{}>{};.

I would find this mostly pointless, so I won't implement it. It should be easy with a decent metaprogramming library, most of the above operations are bog-standard.


Why you shouldn't

But really, given your example, just do this:

template<class...Ts>
struct and_types:std::true_type{};
template<class T0, class...Ts>
struct and_types<T0,Ts...>:std::integral_constant<bool, T0{} && and_types<Ts...>{}>{};

Then:

std::enable_if_t<and_types<std::is_convertible<Args2, Args1>...>{}>

does the job. All of the shuffling is just noise.

With fold ... support from C++1z, we get rid of and_types as well and just use && and ....




回答3:


You can use std::conjuction to fold all result types in one:

template <class... Args>
struct is_convertible_multi {
   constexpr static bool value = false;
};

template <class... Args1, class... Args2>
struct is_convertible_multi<::std::tuple<Args1...>, ::std::tuple<Args2...>> {
   constexpr static bool value =  ::std::conjunction_v<::std::is_convertible<Args1,Args2>...>;
};

And remember to check if

sizeof... (Args1) == sizeof... (Args2)

using if constexpr or enable_if



来源:https://stackoverflow.com/questions/34615570/variadic-version-of-stdis-convertible

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!