Taking the function address and discarding it at compile time: is it really C ++?

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;

// let say we want something with a "regular" operator+

class Thing
{
public:
    Thing operator+(const Thing&){return Thing();} //the kind of operator we want
};

class OtherThing
{
public:
    OtherThing operator+(int){return OtherThing();} // the kind of operator we don't want
};

class YetAnotherThing
{
    // no operator whatsoever
};

// The questionable line. I'm taking the address of the function and 
// immediately discarding it using the comma operator.
#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.

, , , ?

. .

+4
1

-, boost TypeTraits , , - . . -, enable_if, , . , T , static_assert. :

template <typename T>
auto foo(T)
{
    static_assert(boost::has_plus<T, T>::value, "T must support operator+");
    // Impl...
}
+2

Source: https://habr.com/ru/post/1611349/


All Articles