【问题标题】:C++ determine if a container has ::find() [duplicate]C ++确定容器是否具有 ::find() [重复]
【发布时间】:2015-12-12 11:47:54
【问题描述】:

我有一个函子,它在 U 类型的容器上运行,该容器包含 T 类型的元素,就像这样

template<typename T, template<typename...> class U>
class asserter 
{
public:
    asserter(U<T> &c) : container(c) { };
    void operator()(T lhs) 
    {
        CU_ASSERT(container.find(lhs) != container.end());
    };
private:
    U<T>    &container;
};

我可以用作

std::set<std::string> a, c;
...
asserter<std::string, std::set> ass(c);
for_each(a.begin(), a.end(), ass);

我们暂时忽略std::includes()

如果容器是定义了U::find() 的容器,这将非常有用。如果不是,我想回退到std::find()。另一方面,如果可用,我宁愿使用U::find() 而不是std::find()

在 C++11(或 17,如有必要)中,我能否确定 U::find() 是否可用于 U(可能仅限于 STL),如果可以使用它,否则使用 std::find()

【问题讨论】:

    标签: c++ c++11 stl traits sfinae


    【解决方案1】:

    关于表达式 c.find(value) 是否格式正确的 SFINAE。尾随返回类型是 C++11,无论如何在这里都不是必需的;它只是使返回类型更容易编写 - decltype(c.find(value)) 而不是 decltype(std::declval&lt;Container&amp;&gt;().find(std::declval&lt;const T&amp;&gt;()))

    如果表达式格式不正确,则从重载集中删除 find_impl 的第一个重载,而将第二个重载作为唯一可行的重载。第三个参数的常用int/long/0 技巧使第一个重载在两者都可行时首选。

    template<class Container, class T>
    auto find_impl(Container& c, const T& value, int) -> decltype(c.find(value)){
        return c.find(value);
    }
    
    template<class Container, class T>
    auto find_impl(Container& c, const T& value, long) -> decltype(std::begin(c)){
        return std::find(std::begin(c), std::end(c), value);
    }
    
    template<class Container, class T>
    auto find(Container& c, const T& value) -> decltype(find_impl(c, value, 0)) {
        return find_impl(c, value, 0);
    }
    

    通常的免责声明适用:这依赖于表达式 SFINAE,目前 MSVC 不支持该表达式; Microsoft 确实计划在 MSVC 2015 的更新中添加支持。

    【讨论】:

    • 一个更有用的答案也可以解释为什么代码有效。例如,我期待一个使用 SFINAE 的答案。 decltype(...) 部分是 C++17 中的 SFINAE 技术吗(我认为这个 lambda 表达式语法是 C++17)?此外,int 是否用于强制该签名优先于 long 重载?
    • 我担心std::find 是为了等价,而std::set::find 等是为了等价。我们需要考虑这个吗?
    • @NickyC 我知道理论上它们是不同的,但在现实世界中这种情况的频率如何?我认为setmap(以及他们的multi 表亲)是唯一重要的,unordered_setunordered_map 应该使用平等。
    • @JamesAdkison 这是 SFINAE,它从 C++11 开始工作。这里没有 lambda,但这也是 C++11。
    • TIL 用于重载选择的 int/long 技巧。虽然我个人会使用两个基类和派生标签类来更清楚地表达层次结构(如迭代器标签)
    猜你喜欢
    • 1970-01-01
    • 2012-02-08
    • 2014-10-08
    • 2023-03-11
    • 1970-01-01
    • 1970-01-01
    • 2011-07-14
    • 2013-07-23
    • 2012-12-04
    相关资源
    最近更新 更多