2

I would like to have a class which disables/enables member functions based on the value of a template parameter to a class. I have the following:

enum MyType{ type1, type2 };
template <MyType type>
class Test{
    public:
        enum TestTraits{ testType = type };
        template <typename T>
        constexpr bool func(SomethingElse<T> else)
        {
           if(testType == type1) return false;
           // some logic that would return true or false
        }
};

I would basically like to make it a compile time check instead of a runtime check, and that its not even an option for the client to call it if possible. I'm sure the solution is enable_if, but when I see that, it seems like it requires the enable_if to decide the return type or one of the function parameters

Tyler Kelly
  • 564
  • 5
  • 23
  • essentially, yes – Tyler Kelly Apr 28 '20 at 20:04
  • How many different permutations is it going to be? For a simple example of 2 like this, you could just specialize the class for the two different options. – NathanOliver Apr 28 '20 at 20:05
  • just two types, and I have implemented that solution before, but there are a handful of functions that differ within. I was hoping I could get away with just "one" class – Tyler Kelly Apr 28 '20 at 20:08
  • 1
    What you really need is [constexpr if](https://en.cppreference.com/w/cpp/language/if#Constexpr_If), but that is a C++17 feature. Otherwise you can have multiple overloads and use SFINAE like jork just answered. – NathanOliver Apr 28 '20 at 20:15

1 Answers1

2

If I understand you correctly, you'll want one of the following:

enable_if in the return type of the function that you wan't to enable/disable (you can still have the function return bool):

    template <typename T>
    constexpr typename std::enable_if<type != type1, bool>::type 
    func(SomethingElse<T>)
    {
          return true;
    }

or a static assert declaration:

    template <typename T>
    constexpr bool func(SomethingElse<T>)
    {
         static_assert(type != type1, "can't call this with type1...");
         return true;
    }

Third option is moving the function that are to be disabled in a base class. Then specialize that base for type1 and leave it empty:

template<MyType mytype>
struct SpecialStuff {
    bool func();
};

template<>
struct SpecialStuff<type1> {
};

template<MyType mytype>
struct CommonStuff : private SpecialStuff<mytype> {
};
jrok
  • 54,456
  • 9
  • 109
  • 141
  • I'm not sure of `SomethingElse`'s intent, so consider this pseudocode... – jrok Apr 28 '20 at 20:14
  • So i get the following compile error using the first approach: `error: need typename before std::enable_if because std::enable_if is a dependent scope... any ideas? – Tyler Kelly Apr 28 '20 at 20:29
  • Yeah, forgot a `typename`, as the error said... Fixed :) – jrok Apr 28 '20 at 20:31
  • yep, sorry about that, forgot about that little issue – Tyler Kelly Apr 28 '20 at 20:32
  • actually, when I attempt this on a type1 object I get the following error: `no type named 'type' in struct std::enable_if<>` any thoughts? – Tyler Kelly Apr 29 '20 at 13:09
  • The condition that you check in `enable_if` needs to depend on a template parameter somehow, otherwise there is no SFINAE but a hard error instead. See [here](https://stackoverflow.com/questions/13401716/selecting-a-member-function-using-different-enable-if-conditions) for a possible solution. – jrok Apr 29 '20 at 14:18
  • gotcha, got that working. so I if i want to add a third type, and a second "overload" function that handles that type I have to specify some third template parameter to make them different? – Tyler Kelly Apr 30 '20 at 12:59
  • Not sure as I don't how you've setup so far. Show your code and we'll see. – jrok Apr 30 '20 at 17:18