【问题标题】:how to use SFINAE to return (const_)iterator from end() method如何使用 SFINAE 从 end() 方法返回 (const_) 迭代器
【发布时间】:2019-10-18 10:23:27
【问题描述】:

我想创建一个集合包装器,其中 end 方法将从成员中公开。集合本身可能是也可能不是const,所以我无法根据它区分const_iteratoriterator,但内部集合(模板)定义了常量。我认为使用enable_if<is_const<T 会实现这一点,但似乎没有。谢谢你的帮助

#include <cassert>
#include <type_traits>
#include <vector>
#include <algorithm>

template <typename ITEMS>
struct collection {
    ITEMS& _items;

    collection(ITEMS& items) : _items(items) {
    }

    auto find(int i) const {
        return std::find(_items.begin(), _items.end(), i);
    }

    typename std::enable_if_t<std::is_const<ITEMS>::value>::const_iterator
    end() const {
        return _items.end();
    }

    typename std::enable_if_t<!std::is_const<ITEMS>::value>::iterator
    end() const {
        return _items.end();
    }
};

template <typename ITEMS>
collection<ITEMS>
make_collection(ITEMS& items) {
    return collection<ITEMS>(items);
}

int main() {
    std::vector<int> ints = {1, 2, 3};
    auto col = make_collection(ints);                                                                                                
    const auto it = col.find(3);                                                                                                     
    assert(it != col.end());                                                                                                         

    const auto cints = ints;                                                                                                         
    auto ccol = make_collection(cints);                                                                                              
    const auto cit = ccol.find(3);                                                                                                   
    assert(cit != ccol.end());                                                                                                       

    return 0;                                                                                                                        
}    

编辑:仅使用 auto end() const { return _items.end(); } 有效,但我想了解为什么模板魔法不起作用。

【问题讨论】:

  • 只需使用autodecltype
  • 没错,它有效,我想进一步了解为什么这种模板魔法不起作用
  • 呃,std::enable_if_t&lt;std::is_const&lt;ITEMS&gt;::value&gt; 要么是 void,要么是无效的。 typename void::const_iterator 毫无意义。

标签: c++ templates sfinae


【解决方案1】:

您的代码存在 2 个问题。首先,std::enable_if_t 要么无效,要么解析为一个类型。如果您不指定哪种类型,则默认为 void。在您的示例中,您没有指定类型。

第二个问题是成员函数依赖于类模板。模板内的所有代码在实例化时都必须有效。当您使用 cont 容器实例化 collection 时,非常量重载将无法推断出返回类型。但它仍然是类模板的一部分,如果其中一部分失败,编译器不会忽略该部分,但会给出编译错误。

解决这个问题的方法是使end方法都成为模板方法并从类中传递模板参数。这样end 方法在调用之前不会被实例化,如果一个失败,只要另一个工作正常就可以了。

template <typename ITEMS>
struct collection {
    ITEMS& _items;

    collection(ITEMS& items) : _items(items) {
    }

    auto find(int i) const {
        return std::find(_items.begin(), _items.end(), i);
    }

    template <typename T = ITEMS>
    typename std::enable_if_t<std::is_const<T>::value, T>::const_iterator
    end() const {
        return _items.end();
    }

    template <typename T = ITEMS>
    typename std::enable_if_t<!std::is_const<T>::value, T>::iterator
    end() const {
        return _items.end();
    }
};

【讨论】:

    猜你喜欢
    • 2021-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-05
    • 1970-01-01
    • 2023-04-01
    相关资源
    最近更新 更多