大括号初始化器列表的推导指南

问题描述

在标准 C++ 库不可用的环境中使用的实现与 std::initializer_list 非常相似:

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_length;

    constexpr initializer_list( const_iterator array,size_type length ) noexcept : m_array( array ),m_length( length ) {}

public:
    constexpr initializer_list( void ) noexcept : m_array( nullptr ),m_length( 0 ) {}

    /* Number of elements */
    constexpr size_type size( void ) const noexcept {
        return m_length;
    }

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

    /* One past the last element */
    constexpr const_iterator end( void ) const noexcept {
        return begin() + size();
    }
};

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

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

然后这样的 initializer_list<T> 即将在另一个类构造函数中使用:

template<typename T>
struct user {
    user( initializer_list<T> init_values ) { ... }
};

以及将两者结合使用的意图:

user<int> sample { 1,2,3,4,5 };

显然,编译器不知道如何推断大括号初始化列表的类型,以便它使用上面实现的初始化列表。我想应该实现某种推导指南来连接我对 initializer_list 的实现和大括号初始化列表。但我不知道如何实现。

有人可以建议我如何实施所描述的扣除指南吗?

解决方法

在标准 C++ 库不可用的环境中

没有这样的事情。虽然独立的 C++ 实现可以自由地仅实现标准库的一部分,但仍有一些组件所有有效的 C++ 实现必须提供。 std::initializer_list 就是这些组件之一。

因此,如果您拥有有效的 C++11 或更高版本的 C++ 实现,那么您必须拥有 <initializer_list> 标头及其内容。这不是可选的。如果您的实现没有提供,那么它就有缺陷。

它不是可选的原因是 std::initializer_list 的重要功能(即从花括号初始化列表生成)是 C++ 语言 的函数,而不是图书馆的。也就是说,编译器之外的代码不可能使 {} 语法构造成为与 std::initializer_list 行为完全类似的类型。

考虑您的代码:

user<int> sample { 1,2,3,4,5 };

仔细想想,这应该意味着 user<int> 的构造函数将被调用,它带有 5 个参数。毕竟,如果 user 有一个包含 5 个整数参数的构造函数,那就意味着什么。但这不是您想要的意思,对于 vector<int> 来说也不是这个意思。为什么?

因为 C++ 的语言有一个关于列表初始化的特殊规则,它检测构造函数的存在,该构造函数接受一个 std::initializer_list 匹配花括号初始化列表类型,然后创建一个 std::initializer_list 传递给这个构造函数。此规则关闭了接受 std::initializer_list没有其他类型的构造函数的存在。

您的代码不起作用,不是因为缺少演绎指南,而是因为您的 initializer_list 类型在语言方面没有特殊规则。

您无法使用用户定义的类型重新创建此语言行为。就像您不能让 typeid 返回除 std::type_info 之外的类型一样。就像您不能让 enum class byte: unsigned char{}; 具有与 std::byte 相同的行为一样。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...