可以使用另一个模板和递归来生成一组模板类吗?

huangapple go评论86阅读模式
英文:

is it possible to generate a set of template classes by using another template and recursion?

问题

我想创建一些模板类来断言某种类型的数据:

  1. assertType { static constexpr bool v{false}; };
  2. template<> struct assertType<int> { static constexpr bool v{true}; };
  3. template<> struct assertType<bool> { static constexpr bool v{true}; };
  4. template<> struct assertType<float> { static constexpr bool v{true}; };
  5. template<> struct assertType<long> { static constexpr bool v{true}; };

但是,我想以编程方式实现它,所以我考虑定义一个支持的类型“列表”:

  1. template<typename ...Types>
  2. struct TypesList { };
  3. static inline TypesList<int, bool, float, long> supportedTypes;

然后将这个“列表”传递给另一个模板,通过递归为列表中的每个类型生成“assertType”模板。类似于:

  1. template<typename ...Ts>
  2. struct BuildTemplates { };
  3. template<typename ...Ts>
  4. struct BuildTemplates<TypesList<Ts...>> { };
  5. BuildTemplates<supportedTypes> /* 为int、bool、float和long生成模板 */

这样,我可以使用:

  1. assertType<int>::v // v 应该为 true
  2. assertType<bool>::v // v 应该为 true
  3. assertType<float>::v // v 应该为 true
  4. assertType<long>::v // v 应该为 true

任何其他类型的模板,其类型不属于这些类型之一,应将其v值设置为false。

这是否可行?
提前感谢您。

英文:

I want to create a few template classes in order to assert certain type of data:

  1. assertType { static constexpr bool v{false}; };
  2. template&lt;&gt; struct assertType&lt;int&gt; { static constexpr bool v{true}; };
  3. template&lt;&gt; struct assertType&lt;bool&gt; { static constexpr bool v{true}; };
  4. template&lt;&gt;struct assertType&lt;float&gt; { static constexpr bool v{true}; };
  5. template&lt;&gt;struct assertType&lt;long&gt; { static constexpr bool v{true}; };

However, I would like to do it programmatically, So I thought about defining a "list" of the supported types:

  1. template&lt;typename ...Types&gt;
  2. struct TypesList { };
  3. static inline TypesList&lt;int, bool, float, long&gt; supportedTypes;

And have that "list" passed to another template that, by recursion, generates the "assertType" template for every type in the list. Something like:

  1. template&lt;typename ...Ts&gt;
  2. struct BuildTemplates { };
  3. template&lt;typename ...Ts&gt;
  4. struct BuildTemplates&lt;TypesList&lt;Ts...&gt;&gt; { };
  5. BuildTemplates&lt;supportedTypes&gt; /* Build the templates for int, bool, float and long */

So I can use:

  1. assertType&lt;int&gt;::v // v should be true
  2. assertType&lt;bool&gt;::v // v should be true
  3. assertType&lt;float&gt;::v // v should be true
  4. assertType&lt;long&gt;::v // v should be true

Any other template whose type is not one of those, should have its v value set to false.

Is this possible?
Thanks in advance.

答案1

得分: 6

以下是已翻译的内容:

答案在很大程度上取决于您想要的语法。例如,您可以这样做:

  1. #include <type_traits>
  2. template<typename... Types> struct TypeList {};
  3. using SupportedTypes = TypeList<int, bool, float, long>;
  4. template<typename T>
  5. struct assertType {
  6. template<class... Types>
  7. static constexpr bool contains(TypeList<Types...>) {
  8. return (std::is_same_v<T, Types> || ...);
  9. }
  10. static constexpr bool v = contains(SupportedTypes{});
  11. };
  12. static_assert( assertType<int>::v);
  13. static_assert( assertType<bool>::v);
  14. static_assert(!assertType<short>::v);

如果您可以使用boost,可以使用boost::mp11::mp_contains来使实现变得简单:

  1. #include <boost/mp11.hpp>
  2. using SupportedTypes = boost::mp11::mp_list<int, bool, float, long>;
  3. template<typename T>
  4. struct assertType : boost::mp11::mp_contains<SupportedTypes, T> {};
  5. static_assert( assertType<int>::value);
  6. static_assert( assertType<bool>::value);
  7. static_assert(!assertType<short>::value);

或者,如果您想使用v而不是value(这是事实上的标准名称):

  1. template<typename T>
  2. struct assertType {
  3. static constexpr bool v =
  4. boost::mp11::mp_contains<SupportedTypes, T>::value;
  5. };
英文:

The answer mostly depends on the syntax you want to get. For example, you could do this:

  1. #include &lt;type_traits&gt;
  2. template&lt;typename... Types&gt; struct TypeList {};
  3. using SupportedTypes = TypeList&lt;int, bool, float, long&gt;;
  4. template&lt;typename T&gt;
  5. struct assertType {
  6. template&lt;class... Types&gt;
  7. static constexpr bool contains(TypeList&lt;Types...&gt;) {
  8. return (std::is_same_v&lt;T, Types&gt; || ...);
  9. }
  10. static constexpr bool v = contains(SupportedTypes{});
  11. };
  12. static_assert( assertType&lt;int&gt;::v);
  13. static_assert( assertType&lt;bool&gt;::v);
  14. static_assert(!assertType&lt;short&gt;::v);

If you can use boost, boost::mp11::mp_contains could be employed to make the implementation trivial:

  1. #include &lt;boost/mp11.hpp&gt;
  2. using SupportedTypes = boost::mp11::mp_list&lt;int, bool, float, long&gt;;
  3. template&lt;typename T&gt;
  4. struct assertType : boost::mp11::mp_contains&lt;SupportedTypes, T&gt; {};
  5. static_assert( assertType&lt;int&gt;::value);
  6. static_assert( assertType&lt;bool&gt;::value);
  7. static_assert(!assertType&lt;short&gt;::value);

Or if you want to use v instead of value (which is de facto a standard name):

  1. template&lt;typename T&gt;
  2. struct assertType {
  3. static constexpr bool v =
  4. boost::mp11::mp_contains&lt;SupportedTypes, T&gt;::value;
  5. };

答案2

得分: 2

这只有在允许程序化解决方案定义assertType的模板特化或在其模板定义内部使用时才可能。

以下是一个通过在C++11中定义单个assertType部分模板特化的方法:

  1. template <typename>
  2. struct assertType { static constexpr bool v = false; };
  3. template <typename...>
  4. struct TypeList {};
  5. using supportedTypes = TypeList<int, bool, float, long>;
  6. #include <type_traits>
  7. template <typename...>
  8. struct any_of : std::false_type {};
  9. template <typename T, typename U, typename... Us>
  10. struct any_of<T, TypeList<U, Us...>> : any_of<T, TypeList<Us...>> {};
  11. template <typename T, typename... Us>
  12. struct any_of<T, TypeList<T, Us...>> : std::true_type {};
  13. template <typename T>
  14. struct assertType<typename std::enable_if<any_of<T, supportedTypes>::value, T>::type> {
  15. static constexpr bool v = true;
  16. };

你也可以在类模板定义内部直接使用它,而不是定义部分特化:

  1. // 假设 supportedTypes 和 any_of 已经被定义
  2. template <typename T>
  3. struct assertType { static constexpr bool v = any_of<T, supportedTypes>::value; };

C++17中,使用折叠表达式std::bool_constant可以使any_of的定义变得简单许多:

  1. #include <type_traits>
  2. template <typename...>
  3. struct any_of : std::false_type {};
  4. template <typename T, typename... Us>
  5. struct any_of<T, TypeList<Us...>> : std::bool_constant<(... || std::is_same_v<T, Us>)> {};

或者通过使用std::disjunction

  1. #include <type_traits>
  2. template <typename...>
  3. struct any_of : std::false_type {};
  4. template <typename T, typename... Us>
  5. struct any_of<T, TypeList<Us...>> : std::disjunction<std::is_same_v<T, Us>...> {};

最后,在C++20中,你可以使用概念来简化assertType的部分模板特化的定义:

  1. // 假设 supportedTypes 和 any_of 已经被定义
  2. template <typename T, typename L>
  3. concept any_of_v = any_of<T, L>::value;
  4. template <typename>
  5. struct assertType { static constexpr bool v = false; };
  6. template <any_of_v<supportedTypes> T>
  7. struct assertType<T> { static constexpr bool v = true; };
英文:

This is only possible if your programmatic solution is allowed to define a template specialization of assertType, or to be used within its template definition.

Here's an approach by defining a single partial template specialization of assertType in [tag:C++11]:

  1. template &lt;typename&gt;
  2. struct assertType { static constexpr bool v = false; };
  3. template &lt;typename...&gt;
  4. struct TypeList {};
  5. using supportedTypes = TypesList&lt;int, bool, float, long&gt;;
  6. #include &lt;type_traits&gt;
  7. template &lt;typename...&gt;
  8. struct any_of : std::false_type {};
  9. template &lt;typename T, typename U, typename... Us&gt;
  10. struct any_of&lt;T, TypeList&lt;U, Us...&gt;&gt; : any_of&lt;T, TypeList&lt;Us...&gt;&gt; {};
  11. template &lt;typename T, typename... Us&gt;
  12. struct any_of&lt;T, TypeList&lt;T, Us...&gt;&gt; : std::true_type {};
  13. template &lt;typename T&gt;
  14. struct assertType&lt;typename std::enable_if&lt;any_of&lt;T, supportedTypes&gt;, T&gt;::type&gt; {
  15. static constexpr bool v = true;
  16. };

You could also just use it within the class template definition itself rather than defining a partial specialization:

  1. // assuming supportedTypes and any_of have already been defined
  2. template &lt;typename T&gt;
  3. struct assertType { static constexpr bool v = any_of&lt;T, supportedTypes&gt;::value; };

In [tag:C++17] the definition of any_of becomes much simpler with a fold expression and std::bool_constant:

  1. #include &lt;type_traits&gt;
  2. template &lt;typename...&gt;
  3. struct any_of : std::false_type {};
  4. template &lt;typename T, typename... Us&gt;
  5. struct any_of&lt;T, TypeList&lt;Us...&gt;&gt; : std::bool_constant&lt;(... || std::is_same_v&lt;T, Us&gt;)&gt; {};

Or by using std::disjunction:

  1. #include &lt;type_traits&gt;
  2. template &lt;typename...&gt;
  3. struct any_of : std::false_type {};
  4. template &lt;typename T, typename... Us&gt;
  5. struct any_of&lt;T, TypeList&lt;Us...&gt;&gt; : std::disjunction&lt;std::is_same_v&lt;T, Us&gt;...&gt; {};

Finally in [tag:C++20], you can simplify the definition of the assertType partial template specialization using concepts:

  1. // assuming supportedTypes and any_of have already been defined
  2. template &lt;typename T, typename L&gt;
  3. concept any_of_v = any_of&lt;T, L&gt;::value;
  4. template &lt;typename&gt;
  5. struct assertType { static constexpr bool v = false; };
  6. template &lt;any_of_v&lt;supportedTypes&gt; T&gt;
  7. struct assertType&lt;T&gt; { static constexpr bool v = true; };

答案3

得分: 0

除了实例化模板或预处理技巧之外,在C++中没有自动生成声明的方法。每个声明都必须明确写出。

但是,没有必要为列表中的每种类型都进行显式特化。您可以简单地使用一个主模板来进行assertType,并根据列表中的成员设置v成员,或者您可以使用固定数量的部分特化。其他答案提供了执行此操作的方法。

英文:

Except for instantiating a template or preprocessor trickery, there is no way to generate declarations in C++ automatically. Each declaration must be written out explicitly.

But there is no need to have an explicit specialization for each type in the list. You can simply use a single primary template for assertType and set the v member according to membership in the list or you can use a fixed number of partial specializations. The other answers give approaches to do this.

huangapple
  • 本文由 发表于 2023年1月9日 01:37:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/75049988.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定