Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Macro for (SFINAEd) template function

#define BINDINGTEMPLATE template<typename T, typename = typename std::enable_if_t < std::is_same_v<typename std::decay_t<T>, int> || std::is_same_v<typename std::decay_t<T>, std::string> || std::is_same_v<typename std::decay_t<T>, char>>>

Is something like this bad practice?

I am using this function template many times within the same class.

BINDINGTEMPLATE
void myFunction(int x, int y)
{
   // do something specialised based on input template
}

For instance, I need to use it in many functions, like this one :

like image 331
expl0it3r Avatar asked Sep 13 '26 08:09

expl0it3r


1 Answers

Yes, it's a bad practice. Don't use macros for something that can easily be done without them.

You can move that long SFINAE condition into something like

template <typename T> using foo = std::enable_if_t<...>;

And then you can write simply:

template <typename T, typename = foo<T>>
void myFunction(int x, int y)

Alternatively, you could put the condition into a constexpr function or variable template, then write enable_if_t every time you use it.

Also you could use a concept (requires C++20):

template <typename T>
concept foo = std::is_same_v<typename std::decay_t<T>, int> || etc;

template <foo T>
void myFunction(int x, int y)

Note that this use of enable_if_t (regardless of whether you're using a helper using or not) is not very robust, as the user can circumvent it by explicitly specifying the second template parameter.

A better approach is:

template <typename T, std::enable_if_t<..., std::nullptr_t> = nullptr>
void myFunction(int x, int y)

In addition to being foolproof, this also lets you overload the function based on different traits.

The concepts also solve both problems.

like image 73
HolyBlackCat Avatar answered Sep 14 '26 21:09

HolyBlackCat



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!