【问题标题】:Static assert to check map, set, unordered_map, unordered_set静态断言检查 map、set、unordered_map、unordered_set
【发布时间】:2016-10-25 10:22:47
【问题描述】:

我正在编写一个函数,其中我将mapsetunordered_mapunordered_set 的键复制到vector,现在我想添加一个编译时断言以清除错误,如果有的话尝试在该函数中传递vectorlist

template <typename container>
auto CopyKeyToVector(conatiner c)
{
  //static assert to check c is map, unordered map only?


}

知道我们如何做到这一点 - 作为 mapunordered_map 本身的模板化容器

【问题讨论】:

  • 如果你使用c,因为它是一个关联容器,即只调用一个只存在于例如std::mapstd::unordered_map,那么如果调用者传递了一些没有该成员函数的东西,你会得到一个编译器错误。

标签: c++11 c++14 compile-time static-assert


【解决方案1】:

您可以实现和使用is_specialization_of 作为通用解决方案:

template <typename, template <typename...> class>
struct is_specialization_of : std::false_type
{
};

template <template <typename...> class TTemplate, typename... Ts>
struct is_specialization_of<TTemplate<Ts...>, TTemplate> : std::true_type
{
};

template <typename container>
auto CopyKeyToVector(container c)
{
    static_assert(
        is_specialization_of<container, std::map>{} || 
        is_specialization_of<container, std::unordered_map>{}, "");
}

Full example on wandbox.


注意它也可以和std::enable_if一起使用:

template <typename T>
constexpr auto is_map_or_umap = 
    is_specialization_of<T, std::map>{} || 
    is_specialization_of<T, std::unordered_map>{};

template <typename container>
auto CopyKeyToVector(container) -> std::enable_if_t<is_map_or_umap<container>>
{
    // (1)
}

template <typename container>
auto CopyKeyToVector(container) -> std::enable_if_t<!is_map_or_umap<container>>
{
    // (2)
}

int main()
{
    CopyKeyToVector(std::map<int,float>{});           // Calls (1) 
    CopyKeyToVector(std::unordered_map<int,float>{}); // Calls (1)
    CopyKeyToVector(std::vector<int>{});              // Calls (2)  
}

Full example on wandbox.

【讨论】:

    【解决方案2】:

    不要使用静态断言。相反,添加一级间接:

    template <typename C>
    void CopyKeyToVectorImpl(const C& c) { /* ... */ }
    
    template <typename K, typename T, typename Pred, typename Alloc>
    void CopyKeyToVector(const std::map<K, T, Pred, Alloc>& m) {
      CopyKeyToVectorImpl(m);
    }
    
    template <typename K, typename T, typename Hash, typename Eq, typename Alloc>
    void CopyKeyToVector(const std::unordered_map<K, T, Hash, Eq, Alloc>& m) {
      CopyKeyToVectorImpl(m);
    }
    

    (您可以进一步修改Impl 函数,以通过参数化值到键的投影来允许集合在同一洗涤中。)

    【讨论】:

    • static_asserts 简洁的“必须通过map、unordered_map、...”消息相反,错误消息不会是冗长的“找不到过载”吗?
    • @StoryTeller 编译器错误与使用名为CopyKeyToVector 的函数一起使用肯定会提供相当多的线索,不是吗?如果传入说 std::set 或类似名称可能会有点误导,但我认为它可能已经足够清楚了。
    • @erip,我不同意。但是错误信息清晰的主题是主观的,所以我不会争论这一点。
    • @StoryTeller:嗯...取决于你怎么看。根据我的建议,CopyKeyToVector 支持的重载将出现在公开记录的概要中;接受的类型集是签名的一部分,而不是实现的一部分。但确实诊断与 OP 要求的不同。
    猜你喜欢
    • 1970-01-01
    • 2020-08-12
    • 2021-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-12
    • 1970-01-01
    • 2013-06-25
    相关资源
    最近更新 更多