【问题标题】:How do I derive and add new arguments to the base version of the constructor?如何派生新参数并将其添加到构造函数的基本版本?
【发布时间】:2016-10-24 18:48:03
【问题描述】:

我正在尝试使用一些数据成员扩展一个基类,因此除了我的基类需要的构造函数参数之外,还需要一些额外的构造函数参数。我想将第一个构造函数参数转发给基类。这是我尝试过的:

#include <string>
#include <utility>

struct X
{
    X( int i_ ) : i(i_) {}
    int i;
};

struct Y : X
{
    template <typename ...Ts>        // note: candidate constructor not viable: 
    Y( Ts&&...args, std::string s_ ) // requires single argument 's_', but 2 arguments 
//  ^                                // were provided
    : X( std::forward<Ts>(args)... )
    , s( std::move(s_) )
    {}

    std::string s;
};

int main()
{
    Y y( 1, "" ); // error: no matching constructor for initialization of 'Y'
//    ^  ~~~~~
}

但是,编译器(clang 3.8,C++14模式)向我吐出以下错误信息(主要信息也在上面的源代码中,方便阅读):

main.cpp:23:7: error: no matching constructor for initialization of 'Y'
    Y y( 1, "" );
      ^  ~~~~~
main.cpp:13:5: note: candidate constructor not viable: requires single argument 's_', but 2 arguments were provided
    Y( Ts&&...args, std::string s_ )
    ^
main.cpp:10:8: note: candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 2 were provided
struct Y : X
       ^
main.cpp:10:8: note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 2 were provided
1 error generated.

为什么 clang 试图告诉我,我的模板化构造函数只有一个参数,即使参数的数量是可变的?我该如何解决这个问题?

【问题讨论】:

  • 可以在构造函数的开头加上参数吗?函数/构造函数参数列表前面的Ts&amp;&amp;...是非推导上下文...
  • @W.F.为什么不是模板推演上下文?什么时候可以推导出来?
  • @W.F.是的,当我将附加参数放在 Ts&amp;&amp;... 参数包之前时,它会编译。但我想让他们跟风。
  • 不幸的是,由于 c++11 规范,函数模板参数包只有在作为最后一个参数出现时才能推导出来......
  • @W.F.有没有办法解决这个问题?

标签: c++ c++11 inheritance constructor variadic-templates


【解决方案1】:

这是一个可能的解决方案:

#include <string>
#include <utility>
#include<functional>
#include<tuple>
#include<iostream>

struct X
{
    X( int i_ ) : i(i_) {}
    int i;
};

struct Y : X
{
    template<std::size_t... I, typename... A>
    Y(std::integer_sequence<std::size_t, I...>, std::tuple<A...> &&a)
        : X( std::get<I>(a)... ),
          s(std::move(std::get<sizeof...(I)>(a)))
    { }

    template <typename ...Ts>
    Y( Ts&&...args )
        : Y{std::make_index_sequence<sizeof...(Ts)-1>(),
          std::forward_as_tuple(std::forward<Ts>(args)...)}
    { }

    std::string s;
};

int main()
{
    Y y( 1, "foo" );
    std::cout << y.s << std::endl;
}

【讨论】:

  • 不要复制我的解决方案! :)
  • 顺便说一句,第24行不应该有std::tuple&lt;Ts&amp;&amp;...&gt;{std::forward&lt;Ts&gt;(args)...}}吗?
  • 我有点怀疑。我似乎在工作,但从代码中可以看出发生了什么。
  • @skypjack Heh 实际上我没有使用它只是忘了删除它:) 你首先要给出完整的答案......我只是在玩:)
  • @W.F.我知道,我也是。 ;-)
【解决方案2】:

您必须将可变参数移动到参数列表的末尾。

#include <string>
#include <utility>

struct X
{
    X( int i_ ) : i(i_) {}
    int i;
};

struct Y : X
{
    template <typename ...Ts>        
    Y( std::string s_, Ts&&...args )     //   <==== like this
    : X( std::forward<Ts>(args)... )
    , s( std::move(s_) )
    {}

    std::string s;
};

int main()
{
    Y y( "", 1 ); 
}

【讨论】:

    猜你喜欢
    • 2013-11-15
    • 1970-01-01
    • 1970-01-01
    • 2020-01-17
    • 2010-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-11
    相关资源
    最近更新 更多