英文:
is it possible to generate a set of template classes by using another template and recursion?
问题
我想创建一些模板类来断言某种类型的数据:
assertType { static constexpr bool v{false}; };
template<> struct assertType<int> { static constexpr bool v{true}; };
template<> struct assertType<bool> { static constexpr bool v{true}; };
template<> struct assertType<float> { static constexpr bool v{true}; };
template<> struct assertType<long> { static constexpr bool v{true}; };
但是,我想以编程方式实现它,所以我考虑定义一个支持的类型“列表”:
template<typename ...Types>
struct TypesList { };
static inline TypesList<int, bool, float, long> supportedTypes;
然后将这个“列表”传递给另一个模板,通过递归为列表中的每个类型生成“assertType”模板。类似于:
template<typename ...Ts>
struct BuildTemplates { };
template<typename ...Ts>
struct BuildTemplates<TypesList<Ts...>> { };
BuildTemplates<supportedTypes> /* 为int、bool、float和long生成模板 */
这样,我可以使用:
assertType<int>::v // v 应该为 true
assertType<bool>::v // v 应该为 true
assertType<float>::v // v 应该为 true
assertType<long>::v // v 应该为 true
任何其他类型的模板,其类型不属于这些类型之一,应将其v值设置为false。
这是否可行?
提前感谢您。
英文:
I want to create a few template classes in order to assert certain type of data:
assertType { static constexpr bool v{false}; };
template<> struct assertType<int> { static constexpr bool v{true}; };
template<> struct assertType<bool> { static constexpr bool v{true}; };
template<>struct assertType<float> { static constexpr bool v{true}; };
template<>struct assertType<long> { static constexpr bool v{true}; };
However, I would like to do it programmatically, So I thought about defining a "list" of the supported types:
template<typename ...Types>
struct TypesList { };
static inline TypesList<int, bool, float, long> supportedTypes;
And have that "list" passed to another template that, by recursion, generates the "assertType" template for every type in the list. Something like:
template<typename ...Ts>
struct BuildTemplates { };
template<typename ...Ts>
struct BuildTemplates<TypesList<Ts...>> { };
BuildTemplates<supportedTypes> /* Build the templates for int, bool, float and long */
So I can use:
assertType<int>::v // v should be true
assertType<bool>::v // v should be true
assertType<float>::v // v should be true
assertType<long>::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
以下是已翻译的内容:
答案在很大程度上取决于您想要的语法。例如,您可以这样做:
#include <type_traits>
template<typename... Types> struct TypeList {};
using SupportedTypes = TypeList<int, bool, float, long>;
template<typename T>
struct assertType {
template<class... Types>
static constexpr bool contains(TypeList<Types...>) {
return (std::is_same_v<T, Types> || ...);
}
static constexpr bool v = contains(SupportedTypes{});
};
static_assert( assertType<int>::v);
static_assert( assertType<bool>::v);
static_assert(!assertType<short>::v);
如果您可以使用boost
,可以使用boost::mp11::mp_contains
来使实现变得简单:
#include <boost/mp11.hpp>
using SupportedTypes = boost::mp11::mp_list<int, bool, float, long>;
template<typename T>
struct assertType : boost::mp11::mp_contains<SupportedTypes, T> {};
static_assert( assertType<int>::value);
static_assert( assertType<bool>::value);
static_assert(!assertType<short>::value);
或者,如果您想使用v
而不是value
(这是事实上的标准名称):
template<typename T>
struct assertType {
static constexpr bool v =
boost::mp11::mp_contains<SupportedTypes, T>::value;
};
英文:
The answer mostly depends on the syntax you want to get. For example, you could do this:
#include <type_traits>
template<typename... Types> struct TypeList {};
using SupportedTypes = TypeList<int, bool, float, long>;
template<typename T>
struct assertType {
template<class... Types>
static constexpr bool contains(TypeList<Types...>) {
return (std::is_same_v<T, Types> || ...);
}
static constexpr bool v = contains(SupportedTypes{});
};
static_assert( assertType<int>::v);
static_assert( assertType<bool>::v);
static_assert(!assertType<short>::v);
If you can use boost
, boost::mp11::mp_contains
could be employed to make the implementation trivial:
#include <boost/mp11.hpp>
using SupportedTypes = boost::mp11::mp_list<int, bool, float, long>;
template<typename T>
struct assertType : boost::mp11::mp_contains<SupportedTypes, T> {};
static_assert( assertType<int>::value);
static_assert( assertType<bool>::value);
static_assert(!assertType<short>::value);
Or if you want to use v
instead of value
(which is de facto a standard name):
template<typename T>
struct assertType {
static constexpr bool v =
boost::mp11::mp_contains<SupportedTypes, T>::value;
};
答案2
得分: 2
这只有在允许程序化解决方案定义assertType
的模板特化或在其模板定义内部使用时才可能。
以下是一个通过在C++11中定义单个assertType
的部分模板特化的方法:
template <typename>
struct assertType { static constexpr bool v = false; };
template <typename...>
struct TypeList {};
using supportedTypes = TypeList<int, bool, float, long>;
#include <type_traits>
template <typename...>
struct any_of : std::false_type {};
template <typename T, typename U, typename... Us>
struct any_of<T, TypeList<U, Us...>> : any_of<T, TypeList<Us...>> {};
template <typename T, typename... Us>
struct any_of<T, TypeList<T, Us...>> : std::true_type {};
template <typename T>
struct assertType<typename std::enable_if<any_of<T, supportedTypes>::value, T>::type> {
static constexpr bool v = true;
};
你也可以在类模板定义内部直接使用它,而不是定义部分特化:
// 假设 supportedTypes 和 any_of 已经被定义
template <typename T>
struct assertType { static constexpr bool v = any_of<T, supportedTypes>::value; };
在C++17中,使用折叠表达式和std::bool_constant
可以使any_of
的定义变得简单许多:
#include <type_traits>
template <typename...>
struct any_of : std::false_type {};
template <typename T, typename... Us>
struct any_of<T, TypeList<Us...>> : std::bool_constant<(... || std::is_same_v<T, Us>)> {};
或者通过使用std::disjunction
:
#include <type_traits>
template <typename...>
struct any_of : std::false_type {};
template <typename T, typename... Us>
struct any_of<T, TypeList<Us...>> : std::disjunction<std::is_same_v<T, Us>...> {};
最后,在C++20中,你可以使用概念来简化assertType
的部分模板特化的定义:
// 假设 supportedTypes 和 any_of 已经被定义
template <typename T, typename L>
concept any_of_v = any_of<T, L>::value;
template <typename>
struct assertType { static constexpr bool v = false; };
template <any_of_v<supportedTypes> T>
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]:
template <typename>
struct assertType { static constexpr bool v = false; };
template <typename...>
struct TypeList {};
using supportedTypes = TypesList<int, bool, float, long>;
#include <type_traits>
template <typename...>
struct any_of : std::false_type {};
template <typename T, typename U, typename... Us>
struct any_of<T, TypeList<U, Us...>> : any_of<T, TypeList<Us...>> {};
template <typename T, typename... Us>
struct any_of<T, TypeList<T, Us...>> : std::true_type {};
template <typename T>
struct assertType<typename std::enable_if<any_of<T, supportedTypes>, T>::type> {
static constexpr bool v = true;
};
You could also just use it within the class template definition itself rather than defining a partial specialization:
// assuming supportedTypes and any_of have already been defined
template <typename T>
struct assertType { static constexpr bool v = any_of<T, supportedTypes>::value; };
In [tag:C++17] the definition of any_of
becomes much simpler with a fold expression and std::bool_constant
:
#include <type_traits>
template <typename...>
struct any_of : std::false_type {};
template <typename T, typename... Us>
struct any_of<T, TypeList<Us...>> : std::bool_constant<(... || std::is_same_v<T, Us>)> {};
Or by using std::disjunction
:
#include <type_traits>
template <typename...>
struct any_of : std::false_type {};
template <typename T, typename... Us>
struct any_of<T, TypeList<Us...>> : std::disjunction<std::is_same_v<T, Us>...> {};
Finally in [tag:C++20], you can simplify the definition of the assertType
partial template specialization using concepts:
// assuming supportedTypes and any_of have already been defined
template <typename T, typename L>
concept any_of_v = any_of<T, L>::value;
template <typename>
struct assertType { static constexpr bool v = false; };
template <any_of_v<supportedTypes> T>
struct assertType<T> { 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论