代码之家  ›  专栏  ›  技术社区  ›  tuket

spdlog,使用std::initializer_list创建记录器[duplicate]

  •  0
  • tuket  · 技术社区  · 6 年前
    #include <iostream>
    #include <memory>
    
    class Base
    {
    public:
        Base() {}
    };
    
    class Derived : public Base
    {
    public:
        Derived() {}
        Derived(std::initializer_list<std::pair<int, std::shared_ptr<Base>>>) {}
    };
    
    int main(int argc, char ** argv)
    {
        auto example = new Derived({
            { 0, std::make_shared<Derived>() }
        });
    
        return 0;
    }
    

    它起作用了( live preview )通常,但是当我试图使用 std::make_shared std::initializer_list 作为论据,我犯了错误:

    auto example = new Derived({
        { 0, std::make_shared<Derived>({
            { 0, std::make_shared<Derived>() }
        }) }
    });
    

    你可以在这里看到 live preview

    错误:参数太多,无法运行。。。

    只有当我这样做的时候( live preview ):

    auto example = new Derived({
        { 0, std::make_shared<Derived>(std::initializer_list<std::pair<int, std::shared_ptr<Base>>> {
            { 0, std::make_shared<Derived>() }
        }) }
    });
    

    我想知道的是:为什么只有当我通过 作为论据 标准:共享 {{}} 就像这样:

    auto example = new Derived({ { 0, std::make_shared<Base>() } });
    

    有可能 标准:共享

    提前谢谢。

    0 回复  |  直到 10 年前
        1
  •  7
  •   Yakk - Adam Nevraumont    10 年前

    要使其工作,您需要创建一个自定义 make_shared_from_list make_shared 不支持非显式初始值设定项列表。“布莱恩”很好地描述了原因。

    我会用一个traits类来映射一个类型 T 初始化器列表的类型。

    template<class>struct list_init{};// sfinae support
    template<> struct list_init<Derived>{using type=std::pair<int, std::shared_ptr<Base>>;};
    
    template<class T>using list_init_t=typename list_init<T>::type;
    
    template<class T>
    std::shared_ptr<T> make_shared_from_list( std::initializer_list<list_init_t<T>> list ){
      return std::make_shared<T>( std::move(list) );
    }
    

    或者,将 {...} initializer_list<blah> 直接(不是一个演员,而是一个建筑)可能会起作用。

    理论上,充分的反射元编程支持将允许 shared_ptr 要在没有traits类的情况下完成这项工作,还需要一点时间。

        2
  •  18
  •   Brian Bi    10 年前

    为什么

    auto example = new Derived({
        { 0, std::make_shared<Derived>() }
    });
    

    {{ 0, std::make_shared<Derived>() }}
    

    以某种方式与构造器

    Derived::Derived(std::initializer_list<std::pair<int, std::shared_ptr<Base>>>) {}
    

    很明显,初始化器列表的元素,

    { 0, std::make_shared<Derived>() }
    

    需要用于初始化 std::pair<int, std::shared_ptr<Base>> . 然后找到一个包含两个元素的构造器,

    pair::pair (const first_type& a, const second_type& b);
    

    first_type int second_type std::shared_ptr<Base> . 所以我们终于明白了 std::make_shared<Derived>() 隐式转换为 标准::共享端口<基本端口> ,我们可以走了!

    std::shared_ptr<Derived> 需要隐式转换为 在上面的例子中,只是因为这对组合的构造函数需要它。

    std::make_shared<Derived>({
            { 0, std::make_shared<Derived>() }
        })
    

    问题是 make_shared<Derived> 是一个部分专用的函数模板,可以接受任意数量和类型的参数。因此,编译器不知道如何处理初始值设定项列表

    {{0,std::使共享的<派生的>()}
    

    std::initializer_list<std::pair<int, std::shared_ptr<Base>>> . 此外,a 大括号初始化列表 从未被推断为 std::initializer_list<T> 通过模板演绎,所以即使你有

    std::make_shared<Derived>({0, 0})
    

    Derived 有一个合适的构造函数 std::initializer_list<int> std::make_shared<Derived> 无法为其参数推断任何类型。

    怎么解决这个问题?不幸的是,我看不到任何简单的方法。但至少现在你应该知道为什么你写的东西行不通。

    推荐文章