执行std :: initializer_list

时间:2013-08-10 17:07:29

标签: c++ c++11 initializer-list

我一直在研究initializer_list是如何实现的,所以我找到了标准的第18.9节,发现了一个简单的界面。我认为制作我自己的版本MyNamespace::InitializerList和用例:

是有益的
template<class T>
class ArrayPrinter
{
public:
    ArrayPrinter(MyNamespace::InitializerList<T> list)
    {
        for (auto i : list) cout << i << endl;
    }
};

...

ArrayPrinter ap{ {1,2,3} };

我很惊讶地发现这不起作用并且编译器抱怨它找不到合适的构造函数(它想给我3个参数但是第18.9节只描述了一个默认的构造函数)。

经过一番摆弄后,我发现我的班级必须准确命名std::initializer_list才能工作。我也可以将std::initializer_list替换为MyNamespace,但我不能将MyNamespace::InitializerList别名为std::initializer_list

这似乎不是language feature as it depends on the standard library

我的问题的要点是为什么名称如此重要以及它试图传递给构造函数的那3个参数是什么?

3 个答案:

答案 0 :(得分:22)

名称很重要,因为标准说它是。标准需要某种方式让你能够说,“这个构造函数可以传递一个包含类型T的序列值的braced-init-list”。这种方式被命名为“std::initializer_list”。

您无法创建具有initializer_list的所有语言属性的类。您可以制作一个满足标准第18.9节规定类型的条件。但是您会注意到,唯一指定的构造函数是默认构造函数。创建具有实际元素的initializer_list的唯一方法依赖于编译器,而不是用户土地代码。

因此,您无法复制有关initializer_list的所有内容。就像你无法复制std::type_info一样。 C ++标准库不是可选

答案 1 :(得分:0)

此答案并不完全正确。 可能会创建功能全面的std::initializer_list-它只需要满足目标编译器的特定要求即可。

对于GCC和clang,该要求是私有ctor。这是libc ++实现(也可以在GCC 8.3上正常运行):

template<class _Ep>
class initializer_list
{
    const _Ep* __begin_;
    size_t    __size_;
    
    inline
    constexpr
    initializer_list(const _Ep* __b, size_t __s) noexcept
        : __begin_(__b),
          __size_(__s)
    {}
public:
    typedef _Ep        value_type;
    typedef const _Ep& reference;
    typedef const _Ep& const_reference;
    typedef size_t    size_type;
    
    typedef const _Ep* iterator;
    typedef const _Ep* const_iterator;
    
    inline
    constexpr
    initializer_list() noexcept : __begin_(nullptr), __size_(0) {}
    
    inline
    constexpr
    size_t    size()  const noexcept {return __size_;}
    
    inline
    constexpr
    const _Ep* begin() const noexcept {return __begin_;}
    
    inline
    constexpr
    const _Ep* end()   const noexcept {return __begin_ + __size_;}
};

template<class _Ep>
inline
constexpr
const _Ep*
begin(initializer_list<_Ep> __il) noexcept
{
    return __il.begin();
}

template<class _Ep>
inline
constexpr
const _Ep*
end(initializer_list<_Ep> __il) noexcept
{
    return __il.end();
}

答案 2 :(得分:0)

我在自己实现 initializer_list 时遇到问题时发现了这篇文章,发现编写自己的版本非常有用,该版本可以在 msvc、gcc、avr-gcc 和 clang 上编译。 这个问题可能很老,但我想分享我的解决方案,希望其他人觉得它有用:

#include <stddef.h>

namespace std
{
#if defined(__GNUC__)
// Copyright (C) 2008-2020 Free Software Foundation, Inc.
// Copyright (C) 2020 Daniel Rossinsky <danielrossinsky@gmail.com>
//
// This file is part of GCC.
//
// GCC is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3, or (at your option)
// any later version.
//
// GCC is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.

    template<typename T>
    class initializer_list
    {
    public:
        using value_type = T;
        using reference = const T&;
        using const_reference = const T&;
        using size_type = size_t;
        using iterator = const T*;
        using const_iterator = const T*;

    private:
        iterator  m_array;
        size_type m_len;

        // The compiler can call a private constructor.
        constexpr initializer_list(const_iterator itr, size_type st)
            : m_array(itr), m_len(st) { }

    public:
        constexpr initializer_list() noexcept : m_array(0), m_len(0) { }

        // Number of elements.
        constexpr size_type size() const noexcept { return m_len; }

        // First element.
        constexpr const_iterator begin() const noexcept { return m_array; }

        // One past the last element.
        constexpr const_iterator end() const noexcept { return begin() + size(); }
    };
#elif defined(__clang__)
// Copyright (c) 2019 Chandler Carruth <https://github.com/chandlerc>
// Copyright (c) 2018 Louis Dionne <https://github.com/ldionne>
// Copyright (c) 2017 Eric <https://github.com/EricWF>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// ---- LLVM Exceptions to the Apache 2.0 License ----
//
// As an exception, if, as a result of your compiling your source code, portions
// of this Software are embedded into an Object form of such source code, you
// may redistribute such embedded portions in such Object form without complying
// with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
//
// In addition, if you combine or link compiled forms of this Software with
// software that is licensed under the GPLv2 ("Combined Software") and if a
// court of competent jurisdiction determines that the patent provision (Section
// 3), the indemnity provision (Section 9) or other Section of the License
// conflicts with the conditions of the GPLv2, you may retroactively and
// prospectively choose to deem waived or otherwise exclude such Section(s) of
// the License, but only in their entirety and only with respect to the Combined
// Software.

    template<typename T>
    class initializer_list
    {
    private:
        const T* m_first;
        const T* m_last;

    public:
        using value_type      = T;
        using reference       = const T&;
        using const_reference = const T&;
        using size_type       = size_t;
        using iterator        = const T*;
        using const_iterator  = const T*;

        initializer_list() noexcept : m_first(nullptr), m_last(nullptr) {}

        // Number of elements.
        size_t size() const noexcept { return m_last - m_first; }

        // First element.
        const T* begin() const noexcept { return m_first; }

        // One past the last element.
        const T* end() const noexcept { return m_last; }
    };
#elif defined(_MSC_VER)
// Copyright (c) Microsoft Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// ---- LLVM Exceptions to the Apache 2.0 License ----
//
// As an exception, if, as a result of your compiling your source code, portions
// of this Software are embedded into an Object form of such source code, you
// may redistribute such embedded portions in such Object form without complying
// with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
//
// In addition, if you combine or link compiled forms of this Software with
// software that is licensed under the GPLv2 ("Combined Software") and if a
// court of competent jurisdiction determines that the patent provision (Section
// 3), the indemnity provision (Section 9) or other Section of the License
// conflicts with the conditions of the GPLv2, you may retroactively and
// prospectively choose to deem waived or otherwise exclude such Section(s) of
// the License, but only in their entirety and only with respect to the Combined
// Software.

    template<typename T>
    class initializer_list
    {
    public:
        using value_type = T;
        using reference = const T&;
        using const_reference = const T&;
        using size_type = size_t;
        using iterator = const T*;
        using const_iterator = const T*;

        constexpr initializer_list() noexcept : m_first(nullptr), m_last(nullptr) {}

        constexpr initializer_list(const T* first, const T* last) noexcept
            : m_first(first), m_last(last) {}

        // First element.
        constexpr const T* begin() const noexcept { return m_first; }

        // One past the last element.
        constexpr const T* end() const noexcept { return m_last; }

        // Number of elements.
        constexpr size_t size() const noexcept
        {
            return static_cast<size_t>(m_last - m_first);
        }

    private:
        const T* m_first;
        const T* m_last;
    };
#else
    #error "Initializer_list is not supported for this compiler"
#endif

    template<typename T>
    constexpr const T* begin(initializer_list<T> il) noexcept 
    {
        return il.begin();
    }

    template<typename T>
    constexpr const T* end(initializer_list<T> il) noexcept
    {
        return il.end();
    }
}

注意:

我在实现的正上方添加了带有每个实现的许可序言的版权声明,以表明代码应归功于谁并促进合理使用。

IANAL:

唯一正确包含的版权来自 gcc,msvc 版本缺少一年,clang (llvm) 应该将版权分配给我手动完成的贡献者。但是,我不是专家,可能错过/误解了我被允许共享代码的方式。如果是这样,请告诉我,我会立即应用更改。

此外,据我所知,Apache-2.0 仅在一个方向上与 GPLv3 兼容。你可以在 GPLv3 下转授权我的整个代码,但不能在 Apache-2.0 下

工作证明:

我用来证明我的版本有效的例子来自learncpp

  1. Arduino 1.8.9
  2. x86 msvc v19.28
  3. x86-64 clang (trunk)
  4. x86-64 gcc (trunk)