【问题标题】:How can I template with container only?如何仅使用容器进行模板化?
【发布时间】:2014-04-01 12:05:02
【问题描述】:

我不认为我的标题是准确的所以只是去代码。

namespace Fobaizer
{
  template <typename T, typename C>
  static T GetItemFromContainer(const C &container) {
    T item = container[0]; // do something. 0 or iterator
    return item;
  }
}

例子:

MyClass myClass = Fobaizer::GetItemFromContainer<MyClass, vector<MyClass>(myVector);

MyClass myClass = Fobaizer::GetItemFromContainer<MyClass, deque<MyClass>(myDeque);

这里的 C 是任何容器,例如 std::dequestd::vector。我搜索没有任何库(boost、QT 等)的 C98 解决方案

事实上,我正在寻找类似 C# 的 IEnumerable 的东西。

有什么想法吗?

谢谢。

【问题讨论】:

  • 代码不够清晰。 C 是一个类型;你不能C[0]
  • @R.MartinhoFernandes 哦,对不起。我错过了一些东西。我会编辑。

标签: c++ templates containers


【解决方案1】:
template <typename C>
static typename C::value_type GetItemFromContainer(const C & container) {
    typename C::value_type item = container[0]; // do something. 0 or iterator
    return item;
 }

基本上每个容器都定义了成员 typedefs:

 value_type
 reference
 const_reference
 iterator
 const_iterator

所以如果你想通过值返回,你可以使用C::value_type,如果你想通过引用返回,则使用C::reference等等。

【讨论】:

    【解决方案2】:

    我要做的是创建一个测试来检查您是否可以在容器上调用std::beginstd::end。然后使用这些容器的迭代器和std::advance 将您的迭代器推进到您需要它们的位置。

    这种方法的优点是你可以接受不会过载的容器operator[](例如std::list

        #include <utility>
        #include <type_traits>
        #include <vector>
        #include <list>
    
        namespace sfinae_true_details
        {
            template <class>
            struct sfinae_true : std::true_type{};
        }
    
        template <class T>
        auto test_has_begin_end(int) ->
            sfinae_true_details::sfinae_true<decltype(std::begin(std::declval<T>()) ==
                                                      std::end(std::declval<T>())>;        
    
        template <class>
        std::false_type test_has_begin_end(long);
    
        template <class T>
        struct has_begin_end : decltype(test_has_begin_end<T>(0)){};
    
        int main()
        {
            static_assert(has_begin_end<std::vector<int> >::value, "");
            static_assert(has_begin_end<std::list<float> >::value, "");
            static_assert(has_begin_end<int>::value, "Expected to fail here");
            return 0;
        }
    

    那么你的用法是:

          template <typename T, typename C>
          static T GetItemFromContainer(const C &container) {
              static_assert(has_begin_end<C>::value, "Must pass a container for which "
                            "std::begin and std::end are callable");
              T item = *std::begin(container); // do something. 0 or iterator
              auto iter = std::begin(container);
              std::advance(iter, 5);
              item = *iter; // equivalent to container[5] for RandomAccessContainers
              return item;
          }
    

    【讨论】:

    • 感谢您的信息。顺便说一句,我不能使用 c++11。
    【解决方案3】:

    为什么要在 C++ 中做 IEnumerable,迭代器是迭代集合的好选择。

    【讨论】:

    • 一个 IEnumrable,是 C# 中每个容器/集合实现的接口。容器是可迭代的,是的,我使用迭代器 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-21
    • 2020-09-30
    相关资源
    最近更新 更多