Operating under the rule of "there's never anything new under the sun," I doubt that I'm the first person to come up with this trick. I figured I would stumble across something online documenting it eventually, but I haven't yet, so I figured I would ask.
Its purpose is to selectively enable certain functions provided that they're relevant, without using a derived class.
Is there a name for this pattern? And does anyone have any useful information on this pattern or a pattern that operates similarly?
template<typename T, size_t N>
class Point {
public:
template<size_t P, typename T2=void>
using Enable2D = typename std::enable_if<P == 2 && N == P, T2>::type;
template<size_t P, typename T2=void>
using Enable3D = typename std::enable_if<P == 3 && N == P, T2>::type;
template<size_t P, typename T2=void>
using Enable4D = typename std::enable_if<P == 4 && N == P, T2>::type;
template<size_t P, typename T2=void>
using Enable2DOrHigher = typename std::enable_if<P >= 2 && N == P, T2>::type;
template<size_t P, typename T2=void>
using Enable3DOrHigher = typename std::enable_if<P >= 3 && N == P, T2>::type;
template<size_t P, typename T2=void>
using Enable4DOrHigher = typename std::enable_if<P >= 4 && N == P, T2>::type;
//Example use cases
template<size_t P=N>
static Enable2D<P, Point> withAngle(T angle, T magnitude = 1);
template<size_t P=N>
static Enable3D<P, Point> fromAngles(T psi, T theta, T magnitude = 1);
template<size_t P=N>
Enable2DOrHigher<P, T> const& x() const;
template<size_t P=N>
Enable2DOrHigher<P, T> const& y() const;
template<size_t P=N>
Enable2DOrHigher<P> setX(T const& t);
template<size_t P=N>
Enable2DOrHigher<P> setY(T const& t);
template<size_t P=N>
Enable3DOrHigher<P, T> const& z() const;
template<size_t P=N>
Enable3DOrHigher<P> setZ(T const& t);
template<size_t P=N>
Enable4DOrHigher<P, T> const& w() const;
template<size_t P=N>
Enable4DOrHigher<P> setW(T const& t);
};
David Vandevoorde first introduced the acronym SFINAE to describe related programming techniques. We’re talking here about something related to templates, template substitution rules and metaprogramming… which make it a possibly a scary area!
One of the primary uses of SFINAE can be found through enable_if expressions. enable_if is a set of tools, available in the Standard Library since C++11, that internally use SFINAE. They allow to include or exclude overloads from possible function templates or class template specialization.
We moved to an entirely new world, from some complex SFINAE code, some improvements in C++14 and C++17 to a clear syntax in C++20. In this post, we covered theory and examples of SFINAE - a template programming technique that allows you to reject code from the overload resolution sets.
SFINAE is part of the solution (along with tag dispatching ) Another example from foonathan blog - how to use SFINAE and Tag dispatching to construct a range of objects in raw memory space. Ok, but how can we write such SFINAE expressions?
I wouldn't call it a pattern, but it's a known technique.
Mostly reffered to as conditional interface this technique mainly addresses the problem of a compile time toggling mechanism to switch on and off interfaces of a class. The overall process provides the tools to also toggle the existence of members (so the term conditional compilation gets born).
The technique is more or less implemented the way you propose (though the lack of alias templates was not a problem prior to c++11) and the usual problem is the heavy, cluttering, confusing and "ugly" template machinery boilerplate code.
Addressing this issue, A. Alexandrescu gave a presentation about the topic. Initially there's a small mentioning of the needs for such a technique :
The bullet that says
is reffering to your techniques and the need to have compile time conditionals to toggle the existence of functions ( conditional interface ).
The talk goes on to a proposal for a new language feature. Since we all invented the wheel a couple of times he says, why not a new language syntax, that will allow us to perform such things. His joint work with H. Sutter, produced static if
a compile time toggler that would remove the needs for workarounds as the one you mention. A simple use of this would be
template<int D>
struct Vector
{
double coordinates[D];
static if ( D ) {
double x() { return coordinates[0]; }
}
static if ( D > 1 ) {
double y() { return coordinates[1]; }
}
static if ( D > 2 ) {
double z() { return coordinates[2]; }
}
};
OK maybe that's not the smartest use of it but I think I'm communicating the idea.
On the opposing side now, B. Stroustroup has published a paper where after aknowledging the problems static if
is addressing, he explains why it's a flawed concept (pun intended :) ) and its adoption would be a disaster for the language (ouch!).
That was my two cents, judging from the level of the participants in this "conversation" I'd like to have some feedback regarding on which side they're on, or if they're part of the standardization process what will they be voting for.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With