【问题标题】:Compile time creation of class member stl container (const std::array) filled with elements编译时创建填充元素的类成员 stl 容器(const std::array)
【发布时间】:2018-11-21 12:25:44
【问题描述】:

我尝试创建一个最小的示例,因为它可以使用模板。

(MSVC15, c++14)

有2个问题可能相互关联。

问题1:是否可以在编译时创建填充元素的容器类成员(例如std::array)?

    _limited_int_ptr_container _intIndexes
    {
        // _startIntIndex
        // create indexes???
        std::make_shared<_limited_int_>(_startIntIndex), // 10060u  _startStrIndex
        //std::make_shared<_limited_int_>(_startIntIndex + 1),
        //std::make_shared<_limited_int_>(_startIntIndex + 2),
        //...
        std::make_shared<_limited_int_>(_startIntIndex + _maxIntIndexes -1)
    };

问题2:是否可以将多个模板类与一个通用模板参数组合但只组合一次?

    template <class T, size_t Size>
    using _container = const std::array<T, Size>;

    template <class T>
    using _ptr = std::shared_ptr<T>;

    // is it possible to combine this 2 types and use _maxStrIndexes only once?
    using _limited_str_ = IndexStr<_maxStrIndexes>;
    using _limited_str_ptr = _ptr<_limited_str_>;
    using _limited_str_ptr_container = _container<_limited_str_ptr, _maxStrIndexes>;

完整代码:

#include <iostream>
#include <memory>
#include <array>

template<class T, size_t MaxIndex>
class BaseIndex
{
public:
    virtual ~BaseIndex() = default;

    explicit BaseIndex(const size_t index)
        : _maxIndex(MaxIndex), _currentIndex(index) {}

    virtual void DoSmth() = 0;

    friend std::ostream & operator << (std::ostream & ss, BaseIndex & base_index)
    {
        ss << "Max: " << base_index._maxIndex << ". Current: " << base_index._currentIndex << std::endl;
        return ss;
    }

protected:

    const size_t _maxIndex;

    size_t _currentIndex{ 0u };

};

template<size_t MaxIndex>
class IndexStr : public BaseIndex<std::string, MaxIndex>
{
public:
    explicit IndexStr(const size_t index) :BaseIndex(index) {}

    void DoSmth() override { std::cout << IndexStr::_maxIndex; }
};

template<size_t MaxIndex>
class IndexInt :public BaseIndex<int, MaxIndex>
{
public:
    explicit IndexInt(const size_t index) :BaseIndex(index) {}

    void DoSmth() override { std::cout << IndexInt::_maxIndex; }
};

class Manager
{
private:

    static const size_t _startStrIndex{ 11u };
    static const size_t _startIntIndex{ 10060u };

    static const size_t _maxStrIndexes{ 5 };
    static const size_t _maxIntIndexes{ 120 };

public:

    template <class T, size_t Size>
    using _container = const std::array<T, Size>;

    template <class T>
    using _ptr = std::shared_ptr<T>;

    // is it possible to combine this 2 types and use _maxStrIndexes only once?
    using _limited_str_ = IndexStr<_maxStrIndexes>;
    using _limited_str_ptr = _ptr<_limited_str_>;
    using _limited_str_ptr_container = _container<_limited_str_ptr, _maxStrIndexes>;

    // const std::array<std::shared_ptr<IndexStr<_maxStrIndexes>>, _maxStrIndexes> _strIndexes
    _limited_str_ptr_container _strIndexes
    {
        // _startStrIndex
        // create indexes ???
        // std::integer_sequence ???
        std::make_shared<_limited_str_>(_startStrIndex), // 11 = _startStrIndex
        std::make_shared<_limited_str_>(12),
        std::make_shared<_limited_str_>(13),
        std::make_shared<_limited_str_>(14),
        std::make_shared<_limited_str_>(_startStrIndex + _maxStrIndexes - 1)
    };

    // is it possible to combine this 2 types and use _maxIntIndexes only once?
    using _limited_int_ = IndexInt<_maxIntIndexes>;
    using _limited_int_ptr = _ptr<_limited_int_>;
    using _limited_int_ptr_container = _container<_limited_int_ptr, _maxIntIndexes>;

    _limited_int_ptr_container _intIndexes
    {
        // _startIntIndex
        // create indexes???
        std::make_shared<_limited_int_>(_startIntIndex), // 10060u  _startStrIndex
        //...
        std::make_shared<_limited_int_>(_startIntIndex + _maxIntIndexes -1)
    };
};

template <class T, size_t Size >
void Process(const std::array<std::shared_ptr<T>, Size> _array)
{
    for (auto &&baseindex : _array)
        std::cout << *baseindex;
}

int main()
{
    Manager m;

    Process(m._strIndexes);

    //Process(m._intIndexes);

    return 0;
}

Live demo

【问题讨论】:

  • 如果您对编译时数据感兴趣,您应该查看template meta programming。对于组合多个模板类,是的,可以使用template specialization
  • SO 规则:您需要在此处发布完整代码。
  • 请每个问题回答一个问题,顺便说一句,您有两次问题 1
  • @user463035818,我想这些问题可能是相关的。
  • 确定它可以相关,但它仍然应该是一个单独的问题(如果你认为它有帮助,可能每个链接到另一个)

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


【解决方案1】:

关于第一个问题:是的,有可能。如果您可以使用 C++11 和可变参数模板,这甚至非常简单。

要生成索引的编译时列表,您可以使用std::make_index_sequence&lt;N&gt;,它将返回std::index_sequence&lt;0, 1, 2, 3, ..., N-1&gt;。然后,您可以将其与创建编译时数组的函数进行模式匹配:

template <std::size_t... Ns>
constexpr auto fill_it_at_compile_time_impl(std::index_sequence<Ns...>) {
    return std::array<unsigned, sizeof...(Ns)>{ Ns... };
}

template <std::size_t N>
constexpr auto fill_it_at_compile_time() {
    return fill_it_at_compile_time_impl(std::make_index_sequence<N>());
}

如果要为index_sequence 成员添加偏移量,只需在数组初始化中进行:

constexpr auto offset = 10u;
template <std::size_t... Ns>
constexpr auto fill_it_at_compile_time_impl(std::index_sequence<Ns...>) {
    return std::array<unsigned, sizeof...(Ns)>{ (offset+Ns)... };
}

关于第二个问题: 据我了解,是的,这是可能的。首先,创建一个helperstruct来查询_limited_str的索引:

template <typename T>
struct query_max_index; 
template <std::size_t N>
struct query_max_index<IndexStr<N>> {
    static const auto max_index = N;
};

那么,与其直接引用_maxStrIndexes,不如从_limited_str_ptr间接查询:

using _limited_str_ = IndexStr<_maxStrIndexes>;
using _limited_str_ptr = _ptr<_limited_str_>;
using _limited_str_ptr_container = _container<_limited_str_ptr, query_max_index<std::decay_t<decltype(*std::declval<_limited_str_ptr>())>>::max_index>;

【讨论】:

  • +1;但您应该明确指出,std::index_sequencestd::make_index_sequence 仅从 C++14 开始可用。
  • 是的:我们确信 OP 可以使用 C++11,因为他使用std::array、智能指针、using 来定义别名类型、基于范围的 for 循环、统一初始化......
  • 不错的解决方案,我使用了您的方法并修复了一些失误。 template &lt;typename T, size_t Offset, size_t... Is&gt; constexpr auto fill_container_seq(std::index_sequence&lt;Is...&gt;) { return _container&lt;_ptr&lt;T&gt;, sizeof...(Is)&gt;{std::make_shared&lt;T&gt;(Is + Offset)...}; } template&lt;typename T, size_t N, size_t Offset&gt; constexpr auto fill_container() { return fill_container_seq&lt;T, Offset&gt;(std::make_index_sequence&lt;N&gt;{}); }您可以将其发布到您的答案中-因此我将从此处删除它,因为格式错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-24
  • 2016-02-26
相关资源
最近更新 更多