Как создать идеальный конструктор пересылки для вариативного класса, подобного кортежу

Я пытаюсь создать нечто похожее на кортеж, но столкнулся с проблемой при написании конструктора.

Вот код:

#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
}

Теперь это работает нормально, если в качестве инициализаторов передаются простые типы, но не работает, если я пытаюсь передать аргументы в заключенном в фигурные скобки списке инициализаторов для нетривиального объекта.

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

Clang-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)

Хорошо, теперь меня очень, очень любопытно то, что он работает с кортежем! Согласно Стандарту (20.4.2.1) у него есть конструктор, очень похожий на мой.

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

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

    // ...
};

При построении объекта кортежа таким же образом он работает!

Теперь я хотел бы знать:

A) Какого черта? Почему std :: tuple такой особенный и почему компиляторы не выводят правильное количество аргументов?

B) Как я могу заставить это работать?

5
задан fat-lobyte 3 March 2012 в 21:56
поделиться