首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何通过模板构造函数转发C++基和成员初始化器?

如何通过模板构造函数转发C++基和成员初始化器?
EN

Stack Overflow用户
提问于 2022-03-13 22:10:38
回答 1查看 106关注 0票数 1

我想要创建一个模板,其参数B和D是模板实例化中固定数组的基类和元素:

代码语言:javascript
复制
template <class B,class D>
struct fix_array : public B {
    D    myArray[5];
    /**/ fix_array( void ) { cout << "completely default constructed"; }
};

这个很好用。接下来,我想将初始化值传递给B:

代码语言:javascript
复制
template <class... BI>
/**/    fix_array( BI &&... bi )
           : B( std::forward<BI>(bi)... )
           , myArray( )
           {  cout << "This works too, even for multi-argument constructors of B."; }

这也很管用。最后,我的问题是:

如何通过模板构造函数将初始化值传递给D myArray[5];

我设想调用代码的样子如下:

代码语言:javascript
复制
fix_array<B,D>  myVal( { B-initializers }, { { D[0]-initializers }, { D[1]-initializers } } );

但我迷失在各种模板的地狱里。是否所有的D初始化器都必须具有相同的形式?(假设D可以使用intconst char *D &&初始化。)

这是我的测试程序。debug-util.hh定义了一个类Vobject,它在构造、销毁、复制信息时输出信息。

代码语言:javascript
复制
#include <stdio.h>
#include <memory.h>
#include <iostream>
#include <typeinfo>
#include <memory>
#include <vector>

#include "debug-util.hh"     // Defines Vobject and some other info-printing utilities

template <class B, class T>
class fix_array : public B
{
  public:
    T            pData[5];

    /**/         fix_array( void ) : B( ), pData( ) { std::cerr << "completely default construction" << std::endl; }

    template <class... BI>
    /**/         fix_array( BI &&... bi )
                   : B( std::forward<BI>(bi)... )
                   , pData( )
                   {
                       std::cerr << "fix_array Base was initialized" << std:: endl;
                   }
} ;

/*
 * A Vobject has 4 constructors: (void), (int), (int,char*), (int,int,int)
 *
 * It prints information about how it's constructed, when it's copied or moved,
 * and when it's destroyed.
 */

int
main( int, char ** )
{
    fix_array<Vobject,Vobject>   a;                 // These 4 initialize the Base Vobject
    fix_array<Vobject,Vobject>   b( 1 );            // using the various constructors.
    fix_array<Vobject,Vobject>   c( 3, "foobar" );
    fix_array<Vobject,Vobject>   d( 100, 200, 300 );

    // HOW CAN I PASS INITIALIZERS TO THE pDATA ARRAY MEMBERS???

    // fix_array<Vobject,Vobject> x( { 123, "base init" }, { { 1 }, { 2, "xyz" }, { 2, 4, 5 } } );

    std::cerr << "Hello, world" << std::endl;

    return 0;
}

(是的,我知道这是一个愚蠢的程序,使用std::vector等会更明智。)但我有一个更复杂的最终目标,学习如何使用各种模板将帮助我达到这个目标。)

本程序的执行情况:

代码语言:javascript
复制
Vobject@A000()
Vobject@A001()
Vobject@A002()
Vobject@A003()
Vobject@A004()
Vobject@A005()
completely default construction
Vobject@A006(1)
Vobject@A007()
Vobject@A008()
Vobject@A009()
Vobject@A010()
Vobject@A011()
fix_array Base was initialized
Vobject@A012(3, "foobar")
Vobject@A013()
Vobject@A014()
Vobject@A015()
Vobject@A016()
Vobject@A017()
fix_array Base was initialized
Vobject@A018(100,200,300)
Vobject@A019()
Vobject@A020()
Vobject@A021()
Vobject@A022()
Vobject@A023()
fix_array Base was initialized
Hello, world
~Vobject@A023 (was constructed Vobject(void))
~Vobject@A022 (was constructed Vobject(void))
~Vobject@A021 (was constructed Vobject(void))
~Vobject@A020 (was constructed Vobject(void))
~Vobject@A019 (was constructed Vobject(void))
~Vobject@A018 (was constructed Vobject(int,int,int))
~Vobject@A017 (was constructed Vobject(void))
~Vobject@A016 (was constructed Vobject(void))
~Vobject@A015 (was constructed Vobject(void))
~Vobject@A014 (was constructed Vobject(void))
~Vobject@A013 (was constructed Vobject(void))
~Vobject@A012 (was constructed Vobject(int,const char*))
~Vobject@A011 (was constructed Vobject(void))
~Vobject@A010 (was constructed Vobject(void))
~Vobject@A009 (was constructed Vobject(void))
~Vobject@A008 (was constructed Vobject(void))
~Vobject@A007 (was constructed Vobject(void))
~Vobject@A006 (was constructed Vobject(int))
~Vobject@A005 (was constructed Vobject(void))
~Vobject@A004 (was constructed Vobject(void))
~Vobject@A003 (was constructed Vobject(void))
~Vobject@A002 (was constructed Vobject(void))
~Vobject@A001 (was constructed Vobject(void))
~Vobject@A000 (was constructed Vobject(void))
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-03-13 23:21:18

我怀疑你在试图同时传递两个包裹时被卡住了。你可能会被困在那里,因为这是很直观的事情。不幸的是,直觉在这里失败了,因为从赤裸裸的函数参数中推断出的行为方式是直觉所不期望的。跟踪包的行为不同,很难知道第二个包什么时候开始和第一个包结束,而且错误并不总是很清楚。

在这种情况下,我喜欢做标准库所做的事情。std::pair是一种聚合两个元素的类型。它允许通过将参数元组传递给每个元素(构造函数8)来单独(就位)初始化每个元素。这与std::forward_as_tuple协同工作,这是一个标准的函数模板-- does转发。您可以向基和数组提供参数,以执行类似的操作。

剩下的问题只是如何提取元组元素。B在C++17的std::make_from_tuple中很容易实现。myArray没有相同的好处,因为c-样式数组是不规则的类型。不过,我们可以使用委托构造函数和实用程序std::index_sequence来构造数组。我也将在B中使用这种方法,因此总共只需要C++14。

代码语言:javascript
复制
template <class B, class T>
class fix_array : public B
{
public:
    template <class... BRefs, class... DRefs>
    fix_array(std::tuple<BRefs...> bArgs, std::tuple<DRefs...> dArgs)
    : fix_array(std::move(bArgs), std::make_index_sequence<sizeof...(BRefs)>{}, std::move(dArgs), std::make_index_sequence<sizeof...(DRefs)>{})
    {}

private:
    T            pData[5];

    template <class... BRefs, std::size_t... Bidx, class... DRefs, std::size_t... Didx>
    fix_array(std::tuple<BRefs...> bArgs, std::index_sequence<Bidx...>, std::tuple<DRefs...> dArgs,  std::index_sequence<Didx...>)
    : B( std::get<Bidx>(bArgs)... )
    , pData{ std::get<Didx>(dArgs)... }
    {
        std::cerr << "fix_array Base was initialized" << std:: endl;
    }
};

这两个index_sequence参数是标记类型占位符,按顺序包含每个元组元素的索引。它们只是在正确的序号上展开和访问每个元组元素。std::get已经通过正确的引用类型在std::forward_as_tuple完成其操作之后提取元素。

您可以在一个活生生的例子中看到它的作用。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71461265

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档