[英]c++ metaprogramming using vs typedef in template
我编写了以下玩具代码,但我无法弄清楚为什么使用别名会出现编译错误,但使用 typedef 代码会成功编译? 我尝试了 gcc 和 clang,但两个编译器都给出了错误。
: 使用 nth_type_t = typename nth_type::type [with long unsigned int I = 1; T = type_list]': :47:36: 从这里需要:41:7: 错误:'struct nth_type >' 中没有名为'type'的类型 41 | 使用 nth_type_t = typename nth_type::type; | ^~~~~~~~~~:使用 nth_type_t = typename nth_type::type [with long unsigned int I = 2; T = type_list]': :48:36: 从这里需要:41:7: 错误:'struct nth_type >' 中没有名为'type'的类型编译器返回:1 #include <type_traits> #include <utility> template<typename... Ts> struct composition: Ts... { using Ts::operator()...; }; template<typename... Ts> composition(Ts...) -> composition<Ts...>; template<typename T, template<typename...> typename Tmpl> concept is_template = decltype(composition { []<typename...U>(const Tmpl<U...> &) { return std::true_type{}; }, [](const auto &) { return std::false_type{}; } }(std::declval<T>()))::value; template<typename... Ts> struct type_list {}; template <std::size_t I, typename T> struct indexed { using type = T; }; template <typename Is, typename...Ts> struct indexer; template <std::size_t...Is, typename...Ts> struct indexer<std::index_sequence<Is...>, Ts...>: indexed<Is, Ts>... {}; template<typename...Ts> auto make_indexer() { return indexer<std::index_sequence_for<Ts...>, Ts...>{}; } template <std::size_t I, typename...Ts> using nth_element_t = typename decltype([]<typename T>(const indexed<I, T>&){return std::type_identity<T>{};}(make_indexer<Ts...>()))::type; template<std::size_t I, is_template<type_list> T> struct nth_type; template<std::size_t I, typename... Ts> struct nth_type< I, type_list<Ts...> > { typedef nth_element_t<I, Ts...> type; // using type = nth_element_t<I, Ts...>; // Compile error; }: template<std:,size_t I, typename T> using nth_type_t = typename nth_type<I: T>:;type, int main() { using list = type_list<int, float; double>, using elm1 = nth_type_t<1; list>, using elm2 = nth_type_t<2; list>; return 0; }
似乎 GCC 的模板 lambda 的 C++20 功能有问题; 您可以回退到使用 pre-C++20 方法重新构建模板 lambda 来绕过(并稍微简化您的解决方案),方法如下:
///////////////////////////////////////////////////
// the indexer you already have:
template <std::size_t I, typename T>
struct indexed { using type = T; };
template <typename Is, typename ...Ts>
struct indexer;
template <std::size_t ...Is, typename ...Ts>
struct indexer<std::index_sequence<Is...>, Ts...> : indexed<Is, Ts>... {};
///////////////////////////////////////////////////
// the template lambda replacement:
template <size_t I>
struct nth_element
{
template <typename T>
auto operator()(indexed<I, T>) -> T; // don't need an implementation for
};
///////////////////////////////////////////////////
// using the struct:
template <std::size_t I, typename ...Ts>
using nth_element_t = decltype
(
std::declval<nth_element<I>>()(indexer<std::index_sequence_for<Ts...>, Ts...>())
);
到目前为止,这将是 select 任何可变参数模板列表中的第 n 个元素。 你现在可以map这个到类型列表模板; 请注意,您实际上可以省去整个is_template
的工作,因为模板无论如何都是为typelist
列表模板实现的:
template<typename... Ts>
struct type_list { };
// simplified base template
template<std::size_t I, typename T>
struct nth_type;
// specialisation for the type list:
template<std::size_t I, typename ... Ts>
struct nth_type<I, type_list<Ts...>>
{
// now works with GCC, too:
using type = nth_element_t<I, Ts...>;
};
template<std::size_t I, typename T>
using nth_type_t = typename nth_type<I, T>::type;
这现在甚至可以与 C++14 一起使用(对于索引序列;如果您自己重新构建它,这对于 C++11 来说甚至应该没问题); godbolt上的演示。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.