简体   繁体   中英

Using C++ std::enable_if with a normal function?

let's say I have an enumeration:

typedef enum {
  Val1,
  Val2,
  Val3,
  Val4
} vals;

And a function check(vals x) which returns a boolean indicating whether the val is in a specific subset of values in vals .

bool check(vals x) {
  switch(x) {
  case Val1:
  case Val3:
    return true;
  }
  return false;
}

I want to use this function as a condition for the enable_if (the function, as you can see, it's not a function depending on the runtime), to let the users use only those values with the class template.

class MyClass<vals v> {

}

PS: I need the template to make specializations for a method of the class, depending on the template value.

In C++14, just declare the function constexpr and keep the implementation as is.

In C+11 you need to change it to a single return statement:

constexpr bool check(vals x) {
    return x == Val1 || x == Val3;
}

You don't need neither a function nor enable_if to do that.
Here is an example:

enum class vals {
    Val1,
    Val2,
    Val3,
    Val4
};

template<vals v, bool = (v == vals::Val1 || v == vals::Val3)>
class MyClass;

template<vals v>
class MyClass<v, true> { };

int main() {
    MyClass<vals::Val1> ok;
    // MyClass<vals::Val2> ko;
}

This solution has actually a problem: MyClass<vals::Val2, true> ok; is a valid statement.
Anyway, if it fits well mostly depends on the real problem.

If you want to use enable_if you can do this:

#include<type_traits>

enum class vals {
    Val1,
    Val2,
    Val3,
    Val4
};

template<vals v, std::enable_if_t<(v == vals::Val1 || v == vals::Val3)>* = nullptr>
class MyClass { };

int main() {
    MyClass<vals::Val1> ok;
    // MyClass<vals::Val2> ko;
}

Another solution would be using a static_assert :

enum class vals {
    Val1,
    Val2,
    Val3,
    Val4
};

template<vals v>
class MyClass {
    static_assert((v == vals::Val1 || v == vals::Val3), "!");
};

int main() {
    MyClass<vals::Val1> ok;
    // MyClass<vals::Val2> ko;
}

And so on, there exist a bunch of alternatives that does not require a constexpr ed function.

Otherwise let the function be constexpr as mentioned by @nm and that's all.

Thanks for the answer guys. I found another solution that could be even better for my problem. Since I have to implement a specialized method for all of the supported values, I can even put an assertion in the unspecialized method.

template<vals v>
MyClass<v>::method() {
  assert(check(v) && "Unsupported value!");
}

template<>
MyClass<Val1>::method() {
   // do it!
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM