2
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?

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
Jessi
  • 21
  • 5

3 Answers3

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
};

Live demo

Paul Sanders
  • 24,133
  • 4
  • 26
  • 48
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 {
    
};

Demo

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
0

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
};
fabian
  • 80,457
  • 12
  • 86
  • 114
  • Sorry for not editing the question when I got the answer to my question _"Are you using C++20?"_. OP answered _"C++14"_. – Ted Lyngmo Jun 14 '23 at 19:52