如何为类元组的可变参数类创建一个完美的转发构造函数

fat*_*yte 5 c++ constructor variadic-templates perfect-forwarding c++11

我正在尝试创建类似于元组的东西,但是我遇到了编写构造函数的问题.

这是代码:

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

现在,如果将简单类型作为初始化器传递,则可以正常工作,但如果我尝试在大括号括号初始化器列表中传递参数,则不会.

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
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

好吧,现在是什么让我非常,非常好奇的是它适用于元组!根据标准(20.4.2.1),它有一个构造函数,看起来非常像我的.

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

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

    // ...
};
Run Code Online (Sandbox Code Playgroud)

当以相同的方式构造元组对象时,它可以工作!

现在我想知道:

A)到底是什么?为什么std :: tuple如此特殊,为什么编译器不能推断出正确的参数数量?

B)我怎样才能做到这一点?

ipc*_*ipc 6

A)为什么编译器应该知道,那{4, "blub"}是MyType类型而不是tuple<int, const char*>?

B)在构造函数中将ArgTypes更改为Ts:

explicit B(Ts&&... args)
Run Code Online (Sandbox Code Playgroud)

元组也有以下构造函数:

  explicit constexpr tuple(const _Elements&... __elements);
Run Code Online (Sandbox Code Playgroud)

编辑:重点是,调用带有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
}
Run Code Online (Sandbox Code Playgroud)