V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
CismonX
V2EX  ›  问与答

求助,朋友遇到的一道 C++ 面试题

  •  
  •   CismonX · 2020-04-06 06:35:22 +08:00 · 1656 次点击
    这是一个创建于 1717 天前的主题,其中的信息可能已经有所发展或是发生改变。

    题目

    如下是一个简单封装了 std::tuplemy_tuple 类模板实现,请根据以下要求对其进行扩充:(仅允许使用 STL,不允许使用 Boost.MPL 等外部依赖)

    template <typename... Ts>
    struct my_tuple {
    
        using T = std::tuple<Ts...>;
    
        T instance;
    
        template <std::size_t I>
        std::tuple_element_t<I, T>& get() {
            return std::get<I>(instance);
        }
    };
    
    

    (1):支持在编译期向一个 my_tuple<...> 实例中添加更多的类型,语法和预期效果如下所示:

    int main() {
        auto tuple = my_tuple<int>::append<float, char, long>
                                  ::append<bool, double>
                                  ::append<std::vector<int>>();
        std::vector<int>& vector = tuple.get<6>();
    }
    

    (2):在 (1) 的基础上,对 my_tuple 的模板参数进行限制,不允许重复的类型存在,否则在实例化 my_tuple<...> 时抛出编译期错误:

    int main() {
        auto tuple = my_tuple<int, int>();                      // Error!
        auto tuple1 = my_tuple<int, double>::append<double>();  // Error!
    }
    
    

    (3):在 (2) 的基础上,允许根据类型而不是下标,从 my_tuple<...> 实例中获取对应的元素:

    int main() {
        auto tuple = my_tuple<int>::append<std::vector<int>>();
        std::vector<int>& vector = tuple.get<std::vector<int>>();
    }
    
    

    求助

    朋友当时遇到这道题,只写出来第一问,从第二问开始一直通不过编译,面试官看他做不出来就跳过了。

    后来我拿到这道题看了下,感觉挺惊讶的,以前从来没见过 metaprogramming 的面试题。试着做了一下,第一问确实很简单,只要记得 std::tuple_cat 基本上就没问题了,我的解答如下:

    template <typename... Ts>
    struct my_tuple;
    
    template <typename>
    struct unpack_tuple;
    
    template <typename... Ts>
    struct unpack_tuple<std::tuple<Ts...>> {
        using type = my_tuple<Ts...>;
    };
    
    template <typename... Ts>
    using unpack_tuple_t = typename unpack_tuple<Ts...>::type;
    
    template <typename... Ts>
    struct my_tuple {
        using T = std::tuple<Ts...>;
    
        template <typename... Ks>
        using append = unpack_tuple_t<decltype(
            std::tuple_cat(std::declval<T>(), std::declval<std::tuple<Ks...>>()))>;
    
        T instance;
    
        template <std::size_t I>
        std::tuple_element_t<I, T>& get() {
            return std::get<I>(instance);
        }
    };
    

    但是从第二问开始就没有头绪了,隐约感觉应该可以用到 std::index_sequencestd::disjunction,但不知道该如何下手。还请 V 站各位大佬指教。

    4 条回复    2020-04-06 10:42:35 +08:00
    liuy1994g
        1
    liuy1994g  
       2020-04-06 06:41:52 +08:00 via Android
    这也太早了吧
    geelaw
        2
    geelaw  
       2020-04-06 06:45:45 +08:00 via iPhone
    你不需要知道 tuple_cat 或者 index_sequence 或者 disjunction,这些全都可以通过基础手段实现。

    第二个的思路:列表 A 没有重复等价于 (A 是空的) 或 (A 第一个元素不等于其他且 A 去掉第一个后无重复)。

    第三个的思路:可以通过枚举算出一个元素在列表里的位置。
    owwlo
        3
    owwlo  
       2020-04-06 10:34:09 +08:00   ❤️ 1
    稍微修改了一下你的原答案,不好意思可能写得有点乱,有些地方很冗余。在 https://wandbox.org/上简单的测试过~ 出错的地方还请大家指教 ;)

    ```c++
    #include <vector>
    #include <tuple>

    using namespace std;

    template <typename... Ts>
    struct my_tuple;

    template<typename A, typename B>
    struct tuple_contains;

    template <typename checkT>
    struct tuple_contains<std::tuple<>, checkT>
    {
    constexpr static bool value = false;
    };

    template <typename headT, typename checkT>
    struct tuple_contains<std::tuple<headT>, checkT>
    {
    constexpr static bool value = std::is_same<headT, checkT>::value;
    };

    template <typename headT, typename... tailT, typename checkT>
    struct tuple_contains<std::tuple<headT, tailT...>, checkT>
    {
    constexpr static bool value = std::is_same<headT, checkT>::value || tuple_contains<std::tuple<tailT...>, checkT>::value;
    };

    template<typename A, typename B>
    struct tuple_count;

    template <typename checkT>
    struct tuple_count<std::tuple<>, checkT>
    {
    constexpr static size_t value = 0;
    };

    template <typename headT, typename checkT>
    struct tuple_count<std::tuple<headT>, checkT>
    {
    constexpr static size_t value = std::is_same<headT, checkT>::value ? 1 : 0;
    };

    template <typename headT, typename... tailT, typename checkT>
    struct tuple_count<std::tuple<headT, tailT...>, checkT>
    {
    constexpr static size_t value = (std::is_same<headT, checkT>::value ? 1 : 0 ) + tuple_count<std::tuple<tailT...>, checkT>::value;
    };

    template<typename A>
    struct check_tuple_unique;

    template<>
    struct check_tuple_unique<std::tuple<>>
    {
    constexpr static bool value = true;
    };

    template <typename headT>
    struct check_tuple_unique<std::tuple<headT>>
    {
    constexpr static bool value = true;
    };

    template <typename headT, typename... tailT>
    struct check_tuple_unique<std::tuple<headT, tailT...>>
    {
    constexpr static bool value = (tuple_count<std::tuple<tailT...>, headT>::value == 0) && check_tuple_unique<std::tuple<tailT...>>::value == true;
    };

    template<typename A, typename B, typename C>
    struct index_of_details;

    template <typename... leftT, typename headT, typename checkT>
    struct index_of_details<std::tuple<leftT...>, std::tuple<headT>, checkT>
    {
    constexpr static size_t value = std::is_same<headT, checkT>::value ? tuple_size<std::tuple<leftT...>>::value : -1;
    };

    template <typename... leftT, typename headT, typename... tailT, typename checkT>
    struct index_of_details<std::tuple<leftT...>, std::tuple<headT, tailT...>, checkT>
    {
    constexpr static size_t value = std::is_same<headT, checkT>::value ? tuple_size<std::tuple<leftT...>>::value : index_of_details<std::tuple<leftT..., headT>, std::tuple<tailT...>, checkT>::value;
    };

    template<typename A, typename B>
    struct index_of;

    template <typename checkT, typename... tailT>
    struct index_of<std::tuple<tailT...>, checkT>
    {
    constexpr static size_t value = index_of_details<std::tuple<>, std::tuple<tailT...>, checkT>::value;
    };

    template <typename... Ts>
    struct my_tuple {
    using T = std::tuple<Ts...>;

    template <typename... Ks>
    using append = my_tuple<Ts..., Ks...>;

    my_tuple()
    {
    static_assert(check_tuple_unique<T>::value, "Wakaka! duplicated found!");
    }

    T instance;

    template <std::size_t I>
    std::tuple_element_t<I, T>& get() {
    return std::get<I>(instance);
    }

    template<typename targetT>
    auto& get() {
    return std::get<index_of<T, targetT>::value>(instance);
    }

    };


    int main()
    {
    static_assert(tuple_contains<std::tuple<>, int>::value == false, "wrong answer");
    static_assert(tuple_contains<std::tuple<int>, int>::value == true, "wrong answer");
    static_assert(tuple_contains<std::tuple<double, double>, int>::value == false, "wrong answer");

    static_assert(tuple_count<std::tuple<>, int>::value == 0, "wrong answer");
    static_assert(tuple_count<std::tuple<int>, int>::value == 1, "wrong answer");
    static_assert(tuple_count<std::tuple<int, double, int>, int>::value == 2, "wrong answer");

    static_assert(check_tuple_unique<std::tuple<>>::value == true, "wrong answer");
    static_assert(check_tuple_unique<std::tuple<int>>::value == true, "wrong answer");
    static_assert(check_tuple_unique<std::tuple<int, double, int>>::value == false, "wrong answer");
    static_assert(check_tuple_unique<std::tuple<int, int>>::value == false, "wrong answer");
    static_assert(check_tuple_unique<std::tuple<int, double, std::vector<int>>>::value == true, "wrong answer");

    // this will fail
    // auto tuple = my_tuple<int>::append<float, char, long>
    // ::append<bool, double>
    // ::append<std::vector<int>, int>();
    auto tuple = my_tuple<int>::append<float, char, long>
    ::append<bool, double>
    ::append<std::vector<int>>();
    std::vector<int>& vector = tuple.get<6>();
    std::vector<int>& vector2 = tuple.get<std::vector<int>>();

    auto tuple2 = my_tuple<int>::append<std::vector<int>>();
    std::vector<int>& vector3 = tuple.get<std::vector<int>>();
    int& vector4 = tuple.get<int>();
    }
    ```
    owwlo
        4
    owwlo  
       2020-04-06 10:42:35 +08:00
    T T 咋在回复里高亮 c++代码啊?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5351 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 06:54 · PVG 14:54 · LAX 22:54 · JFK 01:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.