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

C++ 11中的混合列表初始化

  •  0
  • ABCplus  · 技术社区  · 6 年前

    关于 c++11 list initialization ,我可以用一个元素和另一个列表初始化一个列表吗?

    假设我有以下代码:

    #include <vector>
    
    class Foo
    {
        public:
            Foo(int value){m_v=value;}
        private:
            int m_v = 0;
    };
    
    int main()
    {
       std::vector<Foo> v1, v2, v3;
       v1 = {Foo(1)}; //ok
       v2 = {Foo(2), Foo(3)}; //ok
       v3 = {Foo(3), v2}; //error: no match for ‘operator=’ (operand types are ‘std::vector’ and ‘’)
    }
    

    有没有一种方法可以使用列表初始化在一行代码中创建一个向量,该向量由另一个向量的元素加上一个新元素(在上面的示例中是一个前缀)组成。

    2 回复  |  直到 6 年前
        1
  •  1
  •   Richard Hodges    6 年前

    我们可以创建一些模板基础设施,允许通过对象和其他向量的可选连接来创建向量。

    这是第一个切入点:

    #include <utility>
    #include <vector>
    
    namespace extended
    {
        template<class T>
        struct appender
        {
            template<class V, class A, class Arg>
            void operator()(std::vector<V, A>& vec, Arg&& arg) const
            {
                vec.push_back(std::forward<Arg>(arg));
            }
        };
    
        template<class V2, class A2>
        struct appender<std::vector<V2, A2>>
        {
            template<class V, class A, class X>
            void operator()(std::vector<V, A>& vec, X&& arg) const
            {
                vec.insert(end(vec), begin(std::forward<X>(arg)), end(std::forward<X>(arg)));
            }
        };
    
        template<class V, class A, class T>
        auto append(std::vector<V, A>& target, T&& x) -> decltype(auto)
        {
            auto op = appender<std::decay_t<T>>();
            op(target, std::forward<T>(x));
            return target;
        }
    }
    
    template<class T, class...Args>
    auto make_vector(Args&&...args)
    {
        using extended::append;
        std::vector<T> result;
        using expand = int[];
        expand {0,
            (append(result, std::forward<Args>(args)), 0)...
        };
        return result;
    }
    
    class Foo
    {
        public:
            Foo(int value){m_v=value;}
        private:
            int m_v = 0;
    };
    
    int main()
    {
       auto v1 = make_vector<Foo>(Foo(1)); //ok
       auto v2 = make_vector<Foo>(Foo(2), Foo(3)); //ok
       auto v3 = make_vector<Foo>(Foo(3), v2); //ok
    }
    

    #include <utility>
    #include <iterator>
    #include <vector>
    #include <list>
    #include <set>
    
    namespace extended
    {
        // The general case of an appender.
        // simply calls emplace_back
        template<class T, class Diff = void>
        struct appender
        {
            template<class V, class A, class Arg>
            void operator()(std::vector<V, A>& vec, Arg&& arg) const
            {
                vec.emplace_back(std::forward<Arg>(arg));
            }
        };
    
        // specific specialisation for an appender where the
        // source object supports begin() and end() (i.e. a container)
        //
        template<class T>
        struct appender
        <
            T, 
            decltype(
                std::begin(std::declval<T>()), 
                std::end(std::declval<T>()),
                void()
            )
        >
        {
            template<class V, class A, class X>
            void operator()(std::vector<V, A>& vec, X&& arg) const
            {
                vec.insert(std::end(vec), std::begin(std::forward<X>(arg)), std::end(std::forward<X>(arg)));
            }
        };
    
        template<class V, class A, class T>
        auto append(std::vector<V, A>& target, T&& x) -> decltype(auto)
        {
            auto op = appender<std::decay_t<T>>();
            op(target, std::forward<T>(x));
            return target;
        }
    }
    
    template<class T, class...Args>
    auto make_vector(Args&&...args)
    {
        using extended::append;
        std::vector<T> result;
        using expand = int[];
        expand {0,
            (append(result, std::forward<Args>(args)), 0)...
        };
        return result;
    }
    
    class Foo
    {
        public:
            Foo(int value){m_v=value;}
    
            bool operator<(const Foo& r) const { return m_v < r.m_v; }
        private:
            int m_v = 0;
    };
    
    
    
    int main()
    {
       auto v1 = make_vector<Foo>(Foo(1)); //ok
       auto v2 = make_vector<Foo>(Foo(2), Foo(3)); //ok
       auto v3 = make_vector<Foo>(Foo(3), v2); //ok
       auto v4 = make_vector<Foo>(Foo(1), 
        std::list<Foo> { Foo(2), Foo(3) }, 
        make_vector<Foo>(4, make_vector<Foo>(8, 9, 10)),
        std::set<Foo> {Foo(6), Foo(7) }); // bizzare but ok
    }
    
        2
  •  1
  •   Vittorio Romeo    6 年前

    std::vector<Foo> 是指 std::vector Foo 实例。这意味着它不能任意存储其他 标准::向量

    v3 = {Foo(3), v2};
    

    std::initializer_list<T> 是一个同质的 T 实例。 标准::向量<Foo> 的列表构造函数 std::initializer_list<Foo> . 没有手动解包就无法实现您想要的 v2 的元素。


    有没有一种方法可以使用列表初始化在一行代码中创建一个向量,该向量由另一个向量的元素加上一个新元素(在上面的示例中是一个前缀)组成。