5

タプルに似たものを作成しようとしていますが、私のコンストラクタの作成に問題が発生しました。ここでタプルのようなvariadicクラスのための完全なフォワーディングコンストラクタを作成する方法

コードです:

#include <tuple> 

template <typename... Ts> 
struct B { 
    template <typename... ArgTypes> 
    explicit B(ArgTypes&&... args) 
    { 
     static_assert(sizeof...(Ts) == sizeof...(ArgTypes), 
      "Number of arguments does not match."); 
    } 
}; 

struct MyType { 
    MyType() = delete; 
    MyType(int x, const char* y) {} 
}; 

int main() 
{ 
    B   <int, char>    a{2, 'c'};      // works 
    B   <int, bool, MyType, char> b{2, false, {4, "blub"}, 'c'}; // fails 
    std::tuple<int, bool, MyType, char> t{2, false, {4, "blub"}, 'c'}; // works 
} 

初期化子として単純型を渡した場合、これは[OK]を動作しますが、私は非自明なためブレースで囲まれた初期化子リストで引数を渡すしようとする場合には、しませんオブジェクト。

GCC-4.7には、以下を発する:

vararg_constr.cpp:21:67: error: no matching function for call to 'B<int, bool, MyType, char>::B(<brace-enclosed initializer list>)' 
vararg_constr.cpp:21:67: note: candidates are: 
vararg_constr.cpp:6:14: note: B<Ts>::B(ArgTypes&& ...) [with ArgTypes = {}; Ts = {int, bool, MyType, char}] 
vararg_constr.cpp:6:14: note: candidate expects 0 arguments, 4 provided 

クラン-3.1以下:

vararg_constr.cpp:21:40: error: no matching constructor for initialization of 
     'B<int, bool, MyType, char>' 
    B   <int, bool, MyType, char> b{2, false,{4, "blub"}, 'c'}; // fails 
             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
vararg_constr.cpp:6:14: note: candidate constructor not viable: requires 2 
     arguments, but 4 were provided 
    explicit B(ArgTypes&&... args) 

[OK]を、今私を非常に作るもの、非常に好奇心が、それはタプルのために働くということです!標準(20.4.2.1)によれば、コンストラクタを持っていますが、これは私のようなものです。

template <class... Types> 
class tuple { 
public: 
    // ... 

    template <class... UTypes> 
    explicit tuple(UTypes&&...); 

    // ... 
}; 

同じ方法でタプルオブジェクトを構築すると、機能します。

私は知りたいと思います:

A)なんで? std :: tupleはなぜ特別なのですか?また、コンパイラーが正しい引数数を推測しないのはなぜですか?

B)この作業を行うにはどうすればよいですか?

答えて

6

A){4, "blub"}は、タイプがMyTypeで、tuple<int, const char*>ではないことをコンパイラーが知っているのはなぜですか?コンストラクタ中のTSに

B)の変更がargTypes:

explicit constexpr tuple(const _Elements&... __elements); 

EDIT

explicit B(Ts&&... args) 

タプルはまた、次のコンストラクタを持たない点であり、CONST &とコンストラクタそのそれはR値と呼ばれ、そうではありません。

template <typename... Ts> 
struct B { 
    explicit B(const Ts&... elements) { std::cout << "A\n"; } 
    template<typename... As, 
      typename = typename std::enable_if<sizeof...(As) == sizeof...(Ts)>::type> 
    explicit B(As&&... elements) { std::cout << "B\n" ;} 
}; 

int main() 
{ 
    MyType m {1, "blub"}; 
    B<int, char>   a{2, 'c'};       // prints B 
    B<bool, MyType, char> b{false, {4, "blub"}, 'c'};   // prints A 
    B<bool, MyType, MyType>c{false, {4, "blub"}, std::move(m)}; // prints A 
} 
+0

A)タプルのコンストラクタに対して、MyTypeではなくタプルであることをコンパイラがどのように認識していますか? B)申し訳ありませんが、私はタプルについて少し詳しく説明してください。 TupleはTsでパラメータ化されています...しかし、私が話しているコンストラクタは、UTypesでさらにパラメータ化されています。 –

+0

私は問題をA)もう少し修正するように編集しました – ipc

+1

部分Aについては、囲みテンプレートのパラメータに '&&'を付けることは、意味を変更してもはや完全な転送ではなくなりますが、 Ts)は望ましくないr値参照を形成する。パートBの場合、右辺値は左辺値「const」に「訂正」されているので、通常は機能しますが、それでも完全な転送はできません。 – Potatoswatter

関連する問題