如何根据条件限制用户定义的模板类型。

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

How to restrict userdefined template types based on a condition

问题

class CMyClass<typename VarTypes>
{
// do something
};

当前代码接受多个VarTypes,例如Type1、Type2,而不受任何条件限制(例如编译器选项)。

我想要根据条件限制VarTypes。有经验吗?

英文:
  1. template&lt;typename VarTypes&gt;
  2. class CMyClass
  3. {
  4. // do something
  5. };

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.:

  1. template&lt;typename T&gt;
  2. class CMyClass
  3. {
  4. #if defined(VARIANT1)
  5. static_assert (std::is_same &lt;T, std::string&gt;::value ||
  6. std::is_same &lt;T, std::vector &lt;int&gt;&gt;::value, &quot;Type not allowed&quot;);
  7. #elif defined(VARIANT2)
  8. ...
  9. #endif
  10. // do something
  11. };

Live demo

英文:

I would keep it simple and just use static_assert, e.g.:

  1. template&lt;typename T&gt;
  2. class CMyClass
  3. {
  4. #if defined(VARIANT1)
  5. static_assert (std::is_same &lt;T, std::string&gt;::value ||
  6. std::is_same &lt;T, std::vector &lt;int&gt;&gt;::value, &quot;Type not allowed&quot;);
  7. #elif defined(VARIANT2)
  8. ...
  9. #endif
  10. // do something
  11. };

Live demo

答案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):

  1. #include <tuple>
  2. #if defined(VARIANT1)
  3. using accepted_types = std::tuple <std::string, std::set<int>>;
  4. #elif defined(VARIANT2)
  5. using accepted_types = std::tuple <std::map<int,int>, std::vector<int>>;
  6. #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):

  1. #include <type_traits>
  2. template <typename T, typename Tuple>
  3. struct has_type;
  4. template <typename T>
  5. struct has_type<T, std::tuple<>> : std::false_type {};
  6. template <typename T, typename U, typename... Ts>
  7. struct has_type<T, std::tuple<U, Ts...>> : has_type<T, std::tuple<Ts...>> {};
  8. template <typename T, typename... Ts>
  9. struct has_type<T, std::tuple<T, Ts...>> : std::true_type {};
  10. template<class T, class V>
  11. static constexpr bool has_type_v = has_type<T, V>::value;

Then enable the template only for those types included in accepted_types:

  1. template <typename VarType,
  2. typename = std::enable_if_t<has_type_v<VarType, accepted_types>>>
  3. class CMyClass {
  4. };

Demo

英文:

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):

  1. #include &lt;tuple&gt;
  2. #if defined(VARIANT1)
  3. using accepted_types = std::tuple &lt;std::string, std::set&lt;int&gt;&gt;;
  4. #elif defined(VARIANT2)
  5. using accepted_types = std::tuple &lt;std::map&lt;int,int&gt;, std::vector&lt;int&gt;&gt;;
  6. #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):

  1. #include &lt;type_traits&gt;
  2. template &lt;typename T, typename Tuple&gt;
  3. struct has_type;
  4. template &lt;typename T&gt;
  5. struct has_type&lt;T, std::tuple&lt;&gt;&gt; : std::false_type {};
  6. template &lt;typename T, typename U, typename... Ts&gt;
  7. struct has_type&lt;T, std::tuple&lt;U, Ts...&gt;&gt; : has_type&lt;T, std::tuple&lt;Ts...&gt;&gt; {};
  8. template &lt;typename T, typename... Ts&gt;
  9. struct has_type&lt;T, std::tuple&lt;T, Ts...&gt;&gt; : std::true_type {};
  10. template&lt;class T, class V&gt;
  11. static constexpr bool has_type_v = has_type&lt;T, V&gt;::value;

Then enable the template only for those types included in accepted_types:

  1. template &lt;typename VarType,
  2. typename = std::enable_if_t&lt;has_type_v&lt;VarType, accepted_types&gt;&gt;&gt;
  3. class CMyClass {
  4. };

Demo

答案3

得分: 0

  1. **免责声明:** 此答案需要C++20,并且是在问题添加C++14要求信息之前发布的。
  2. 您可以定义一个类模板,该类模板继承自`std::bool_constant``std::true_type``std::false_type`,具体取决于预处理器定义,可能需要使用特化。这允许您使用类模板创建一个概念,用于限制与您的类模板一起使用的类型参数。
  3. ```cpp
  4. template<class T, class ... Args>
  5. inline constexpr bool IsAnyOf_v = (std::is_same_v<T, Args> || ...);
  6. template<class T>
  7. struct IsAllowed;
  8. #ifdef VARIANT1
  9. // 你可以在定义中提供一切...
  10. template<class T>
  11. struct IsAllowedType : std::bool_constant<IsAnyOf_v<T, int, char>> {};
  12. #elif defined(VARIANT2)
  13. // ...或提供默认值,并为特定类型进行特化
  14. template<class T>
  15. struct IsAllowedType : std::false_type {};
  16. template<>
  17. struct IsAllowedType<unsigned> : std::true_type {};
  18. #else
  19. #error 未知的变体
  20. #endif
  21. template<class T>
  22. concept AllowedType = IsAllowedType<T>::value;
  23. ...
  24. template<AllowedType VarTypes>
  25. class CMyClass
  26. {
  27. // 做一些事情
  28. };
  1. <details>
  2. <summary>英文:</summary>
  3. **Disclaimer:** This answer requires C++20 and was posted before the information about the C++14 requirement was added to the question.
  4. 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
};

  1. </details>

huangapple
  • 本文由 发表于 2023年6月15日 03:21:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76476917.html
匿名

发表评论

匿名网友

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

确定