可变版本的std :: is_convertible?

use*_*683 8 c++ variadic-templates

是否可以编写可变版本的std::is_convertible?例如are_convertible<T1, T2, T3, T4>会返回is_convertible<T1, T3> && is_convertible<T2, T4>.我一直在考虑这个问题几个小时但是无法提出任何合理的建议.

澄清我想使用它有点像这样:

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

小智 12

你并不需要连接Args2...Args1...,你不应该,因为这样做,以使得它使得它不可能知道Args2...结束和Args1...开始.以允许单独提取它们的方式传递多个可变参数的方法是将它们包装在另一个模板中:给定一个可变参数模板my_list,您可以将您的结构my_convertible称为

my_convertible<my_list<Args2...>, my_list<Args1...>>
Run Code Online (Sandbox Code Playgroud)

标准库已经有一个可变的模板,在这里运行良好:tuple.不仅如此,而且tuple<Args2...>可转换为tuple<Args1...>if且仅当Args2...可转换为Args1...,所以你可以写:

std::is_convertible<std::tuple<Args2...>, std::tuple<Args1...>>
Run Code Online (Sandbox Code Playgroud)

注意:在评论中,@ zatm8报告这并不总是有效:std::is_convertible<std::tuple<const char *&&>, std::tuple<std::string &&>>::value报告为false,但std::is_convertible<const char *&&, std::string &&>::value报告为true.

我相信这是一个错误,它们都应该被报告为true.这个问题可以在http://gcc.godbolt.org/和clang 3.9.1 上重现.它不能用gcc 6.3重复,并且在使用时也不能用clang 3.9.1重现-stdlib=libc++.似乎libstdc ++正在使用clang不能正确处理的语言功能,并将其简化为一个不依赖于标准库头的简短示例,它给出了:

struct S {
  S(const char *) { }
};
int main() {
  const char *s = "";
  static_cast<S &&>(s);
}
Run Code Online (Sandbox Code Playgroud)

这被gcc接受,但被clang拒绝.它在2014年报告为https://llvm.org/bugs/show_bug.cgi?id=19917.

看起来这已经在2016年底修复,但修复程序还没有发布到发布版本:http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20161031/175955. HTML

如果您受此影响,您可能希望避免std::tuple使用@Yakk的答案.


Yak*_*ont 7

是.

首先,如何做到这一点.那么,为什么你不应该这样做.

怎么做:

写重组,它取一个kN元素列表并将其分组为N组k,交错.团体可以template<class...>struct types{};.

然后编写apply,它接受一个template<class...>class Z和一个class...组(又名types<...>),并应用于Z每个包的内容,返回types<...>结果的一个.

然后折叠types<...>使用的内容template<class A, class B> struct and_types:std::integral_constant<bool, A{}&&B{}>{};.

我会发现这大多没有意义,所以我不会实现它.使用一个像样的元编程库应该很容易,上面的大多数操作都是沼泽标准的.


为什么你不应该

但实际上,举个例子,就这样做:

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

然后:

std::enable_if_t<and_types<std::is_convertible<Args2, Args1>...>{}>
Run Code Online (Sandbox Code Playgroud)

做的工作.所有的洗牌都只是噪音.

通过...C++ 1z的折叠支持,我们也可以摆脱and_types使用&&....