英文:
How to restrict userdefined template types based on a condition
问题
class CMyClass<typename VarTypes>
{
// do something
};
当前代码接受多个VarTypes,例如Type1、Type2,而不受任何条件限制(例如编译器选项)。
我想要根据条件限制VarTypes。有经验吗?
英文:
template<typename VarTypes>
class CMyClass
{
// do something
};
currently the code accepts multiple VarTypes Type1, Type2 irrespective of any condition (example compiler option).
I have to like to restrict VarTypes based on the conditions. any experience?
答案1
得分: 3
I would keep it simple and just use static_assert
, e.g.:
template<typename T>
class CMyClass
{
#if defined(VARIANT1)
static_assert (std::is_same <T, std::string>::value ||
std::is_same <T, std::vector <int>>::value, "Type not allowed");
#elif defined(VARIANT2)
...
#endif
// do something
};
英文:
I would keep it simple and just use static_assert
, e.g.:
template<typename T>
class CMyClass
{
#if defined(VARIANT1)
static_assert (std::is_same <T, std::string>::value ||
std::is_same <T, std::vector <int>>::value, "Type not allowed");
#elif defined(VARIANT2)
...
#endif
// do something
};
答案2
得分: 2
You could define a std::tuple
based type to describe the accepted types and then use SFINAE to enable instantiating a class from the template based on that.
Example (replace with your own types as needed):
#include <tuple>
#if defined(VARIANT1)
using accepted_types = std::tuple <std::string, std::set<int>>;
#elif defined(VARIANT2)
using accepted_types = std::tuple <std::map<int,int>, std::vector<int>>;
#endif
Then we need a has_type
type trait to check if one type is included in a std::tuple
based type (see link to that answer for the full description):
#include <type_traits>
template <typename T, typename Tuple>
struct has_type;
template <typename T>
struct has_type<T, std::tuple<>> : std::false_type {};
template <typename T, typename U, typename... Ts>
struct has_type<T, std::tuple<U, Ts...>> : has_type<T, std::tuple<Ts...>> {};
template <typename T, typename... Ts>
struct has_type<T, std::tuple<T, Ts...>> : std::true_type {};
template<class T, class V>
static constexpr bool has_type_v = has_type<T, V>::value;
Then enable the template only for those types included in accepted_types
:
template <typename VarType,
typename = std::enable_if_t<has_type_v<VarType, accepted_types>>>
class CMyClass {
};
英文:
You could define a std::tuple
based type to describe the accepted types and then use SFINAE to enable instantiating a class from the template based on that.
Example (replace with your own types as needed):
#include <tuple>
#if defined(VARIANT1)
using accepted_types = std::tuple <std::string, std::set<int>>;
#elif defined(VARIANT2)
using accepted_types = std::tuple <std::map<int,int>, std::vector<int>>;
#endif
Then we need a has_type
type trait to check if one type is included in a std::tuple
based type (see link to that answer for the full description):
#include <type_traits>
template <typename T, typename Tuple>
struct has_type;
template <typename T>
struct has_type<T, std::tuple<>> : std::false_type {};
template <typename T, typename U, typename... Ts>
struct has_type<T, std::tuple<U, Ts...>> : has_type<T, std::tuple<Ts...>> {};
template <typename T, typename... Ts>
struct has_type<T, std::tuple<T, Ts...>> : std::true_type {};
template<class T, class V>
static constexpr bool has_type_v = has_type<T, V>::value;
Then enable the template only for those types included in accepted_types
:
template <typename VarType,
typename = std::enable_if_t<has_type_v<VarType, accepted_types>>>
class CMyClass {
};
答案3
得分: 0
**免责声明:** 此答案需要C++20,并且是在问题添加C++14要求信息之前发布的。
您可以定义一个类模板,该类模板继承自`std::bool_constant`、`std::true_type`或`std::false_type`,具体取决于预处理器定义,可能需要使用特化。这允许您使用类模板创建一个概念,用于限制与您的类模板一起使用的类型参数。
```cpp
template<class T, class ... Args>
inline constexpr bool IsAnyOf_v = (std::is_same_v<T, Args> || ...);
template<class T>
struct IsAllowed;
#ifdef VARIANT1
// 你可以在定义中提供一切...
template<class T>
struct IsAllowedType : std::bool_constant<IsAnyOf_v<T, int, char>> {};
#elif defined(VARIANT2)
// ...或提供默认值,并为特定类型进行特化
template<class T>
struct IsAllowedType : std::false_type {};
template<>
struct IsAllowedType<unsigned> : std::true_type {};
#else
#error 未知的变体
#endif
template<class T>
concept AllowedType = IsAllowedType<T>::value;
...
template<AllowedType VarTypes>
class CMyClass
{
// 做一些事情
};
<details>
<summary>英文:</summary>
**Disclaimer:** This answer requires C++20 and was posted before the information about the C++14 requirement was added to the question.
You could define a class template that inherits from `std::bool_constant`, `std::true_type` or `std::false_type` depending on the preprocessor definitions, possibly using specializations. This allows you to use the class template to create a concept for restricting the type arguments used with your class template.
template<class T, class ... Args>
inline constexpr bool IsAnyOf_v = (std::is_same_v<T, Args> || ...);
template<class T>
struct IsAllowed;
#ifdef VARIANT1
// you could provide everything in the definition...
template<class T>
struct IsAllowedType : std::bool_constant<IsAnyOf_v<T, int, char>> {};
#elif defined(VARIANT2)
// ...or provide a default and specialize for specific types
template<class T>
struct IsAllowedType : std::false_type {};
template<>
struct IsAllowedType<unsigned> : std::true_type {};
#else
#error unknown variant
#endif
template<class T>
concept AllowedType = IsAllowedType<T>::value;
...
template<AllowedType VarTypes>
class CMyClass
{
// do something
};
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论