I was looking for a way to limit template type parameters to those who implement the functions of this signature. I seem to have come up with a rather elegant solution that allows self-documenting code and fairly clean Concept-like error messages. The only problem is that I'm not sure if this is valid C ++ or something that just works in clang and gcc.
Here is the code:
#include <type_traits>
using std::enable_if;
class Thing
{
public:
Thing operator+(const Thing&){return Thing();}
};
class OtherThing
{
public:
OtherThing operator+(int){return OtherThing();}
};
class YetAnotherThing
{
};
#define HAS_FUNCTION(type, ret, name, args...) (static_cast<ret (type::*)(args)>(&type::name), 1)
#define T_HAS_OPERATOR_PLUS HAS_FUNCTION(T, T, operator+, const T&)
template <typename T>
typename enable_if<T_HAS_OPERATOR_PLUS>::type foo(T)
{
T t1, t2;
t1 + t2;
}
#undef T_HAS_OPERATOR_PLUS
int main()
{
Thing t;
OtherThing ot;
YetAnotherThing yat;
foo(t);
foo(ot);
foo(yat);
}
When building with clang, it produces the following output:
main.cpp:43:2: error: no matching function for call to 'foo'
foo(ot);
^~~
main.cpp:29:47: note: candidate template ignored: substitution failure [with T = OtherThing]: static_cast from 'OtherThing (OtherThing::*)(int)' to 'OtherThing (OtherThing::*)(const OtherThing &)' is not allowed
typename enable_if<T_HAS_OPERATOR_PLUS>::type foo(T)
~~~~~~~~~~~~~~~~~~~ ^
main.cpp:44:2: error: no matching function for call to 'foo'
foo(yat);
^~~
main.cpp:29:47: note: candidate template ignored: substitution failure [with T = YetAnotherThing]: no member named 'operator+' in 'YetAnotherThing'
typename enable_if<T_HAS_OPERATOR_PLUS>::type foo(T)
~~~~~~~~~~~~~~~~~~~ ^
2 errors generated.
... that looks pretty pretty compared to a regular secret blizzard.
So my question is: is this really in standard C ++ 14? In the end, I take the address at compile time, it looks like it would be forbidden by the standard.
, , , ?
. .