如下是一个简单封装了 std::tuple
的 my_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_sequence
和 std::disjunction
,但不知道该如何下手。还请 V 站各位大佬指教。
1
liuy1994g 2020-04-06 06:41:52 +08:00 via Android
这也太早了吧
|
2
geelaw 2020-04-06 06:45:45 +08:00 via iPhone
你不需要知道 tuple_cat 或者 index_sequence 或者 disjunction,这些全都可以通过基础手段实现。
第二个的思路:列表 A 没有重复等价于 (A 是空的) 或 (A 第一个元素不等于其他且 A 去掉第一个后无重复)。 第三个的思路:可以通过枚举算出一个元素在列表里的位置。 |
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>(); } ``` |
4
owwlo 2020-04-06 10:42:35 +08:00
T T 咋在回复里高亮 c++代码啊?
|