2016-01-05 6 views
7

std::is_convertibleの可変版を書くことはできますか?たとえば、are_convertible<T1, T2, T3, T4>は、is_convertible<T1, T3> && is_convertible<T2, T4>を返します。私はこれについて数時間考えていましたが、合理的な何かを考え出すことができませんでした。Varidicバージョンのstd :: is_convertible?

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

場合は使用して

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

場合6つのテンプレートは 'がある場合はどう(T1、T2、T3、T4、T5、T6) '? 'is_convertible && is_convertible && is_convertible 'というように、隣人をグループ化する方が良いかもしれないようです。 – erip

+0

@erip次に、2つのパラメータパックから引数をインターリーブする必要があります。 – user697683

+0

なぜインターリーブする必要がありますか? – erip

答えて

11

Args2...Args1...を連結する必要はありません。それで、Args2...がどこで終了し、Args1...がどこから始まるのかを知ることができなくなります。それらを個別に抽出することを可能にする方法で、複数の可変長引数を渡す方法は、さらに別のテンプレートでそれらをラップしている:可変長引数テンプレートmy_list与え、あなたは

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

標準ライブラリとして呼ばれるように、あなたのmy_convertibleを構造化することができすでにここでうまく動作するバリデーショナルテンプレートがあります:tuple。それだけでなく、tuple<Args2...>場合tuple<Args1...>に変換され、あなただけ書くことができますのでArgs2...は、Args1...に変換する場合にのみ:

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

注:コメント欄で、zatm8はこれがないことを報告します@常に動作します:std::is_convertible<std::tuple<const char *&&>, std::tuple<std::string &&>>::valuefalseと報告されていますが、std::is_convertible<const char *&&, std::string &&>::valuetrueと報告されています。

これはバグであり、両方ともtrueと報告されているはずです。この問題は、clang 3.9.1のhttp://gcc.godbolt.org/で再現可能です。 gcc 6.3では再現性がなく、-stdlib=libc++を使用するとclang 3.9.1で再現できません。のlibstdC++かなり正しく処理しません打ち鳴らす言語機能を使用して、標準ライブラリヘッダに依存しない短い例にそれを軽減さが与える表示されます。

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

これは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さん@使用することができます代わりに答えてください。

+0

これは最高の答えです、ありがとう! – user697683

+0

タプルはすべて有効な解決法ではありません。例:std :: is_convertible_v 、std :: tuple >はfalseを返しますが、std :: is_convertible_v zatm8

+0

@ zatm8コメントありがとうございました。私はこれがコンパイラのバグだと思う、私の編集を参照してください。 – hvd

7

はい:私は多少このようにそれを使用したい明確にする

まず、方法。それで、なぜあなたはそれをしてはいけないのですか? K、インターリーブさのN個のグループにkNの要素とグループそれのリストを取り

書き込み再グループ化を、:それを行うにはどのように

。グループはtemplate<class...>struct types{};です。 template<class...>class Zとグループのclass...(別名types<...>)を取り、結果のtypes<...>を返す、束の各々の内容Zを適用

Applyを書き込み、。

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

を:

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

は仕事をしていません。すべてのシャフリングはちょうどノイズです。 C++ 1Zから倍...支援を

は、我々としてもand_typesを取り除くだけ&&...を使用します。

+1

再グループ化や実装例へのリンクの記述方法を教えてください。私の好奇心を満たすことができます:) – YSC

+1

対応する 'tuple'が割り当て可能かどうかをチェックすることもできますが、その解決策があなたの提案したものより簡単に出てくるかどうかはわかりません。 – SirGuy

+0

@ysc私は多くの醜い方法を考えることができます。かなりの意味で、lisp(またはhaskell)のプログラムを誰かに尋ねてから、TMPが動作するはずのC++に翻訳してください。私は、get_every_nthとpop_front_thenを意味し、バインドは1つであるか、N(インタリーブされていない)のk個のグループにグループ分けされ、次に回転されます。すべて乱雑です。したがって、美しいリストプリミティブで言語を見つけ、それらを実装します。 – Yakk

0

あなたは1で、すべての結果の種類を折るためにstd::conjuctionを使用することができます。

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

、チェックすることを忘れないconstexprのかenable_if

関連する問題