#include <iostream>
#include <type_traits>
template<typename T, typename = void>
struct HasFoo: std::false_type
{};
template<typename T>
struct HasFoo<T, std::enable_if_t<std::is_same<decltype(std::declval<T>().foo()), void>::value>>: std::true_type
{};
template<typename T>
constexpr bool HasFoo_v = HasFoo<T>::value;
template<bool B, typename F>
struct ConditioanlCall
{
ConditioanlCall(F function)
{}
};
template<typename F>
struct ConditioanlCall<true, F>
{
ConditioanlCall(F function)
{
auto ignore = false;
function(ignore);
}
};
template<bool B, typename F>
void callConditional(F&& function)
{
ConditioanlCall<B, F>{std::forward<F>(function)};
}
#define CONSTEXPR_IF(condition, action) \
callConditional<condition>([&](auto) action);
struct A
{
void foo()
{
std::cout << "From class foo!\n";
}
};
struct B {};
void foo(B)
{
std::cout << "From standalone foo!\n";
}
void foo(A)
{
std::cout << "From standalone foo!\n";
}
int main()
{
A a;
B b;
CONSTEXPR_IF(!HasFoo_v<B>, {foo(b);});
CONSTEXPR_IF(HasFoo_v<A>, {a.foo();});
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8dHlwZV90cmFpdHM+Cgp0ZW1wbGF0ZTx0eXBlbmFtZSBULCB0eXBlbmFtZSA9IHZvaWQ+CnN0cnVjdCBIYXNGb286IHN0ZDo6ZmFsc2VfdHlwZQp7fTsKCnRlbXBsYXRlPHR5cGVuYW1lIFQ+CnN0cnVjdCBIYXNGb288VCwgc3RkOjplbmFibGVfaWZfdDxzdGQ6OmlzX3NhbWU8ZGVjbHR5cGUoc3RkOjpkZWNsdmFsPFQ+KCkuZm9vKCkpLCB2b2lkPjo6dmFsdWU+Pjogc3RkOjp0cnVlX3R5cGUKe307Cgp0ZW1wbGF0ZTx0eXBlbmFtZSBUPgpjb25zdGV4cHIgYm9vbCBIYXNGb29fdiA9IEhhc0ZvbzxUPjo6dmFsdWU7Cgp0ZW1wbGF0ZTxib29sIEIsIHR5cGVuYW1lIEY+CnN0cnVjdCBDb25kaXRpb2FubENhbGwKewogICAgQ29uZGl0aW9hbmxDYWxsKEYgZnVuY3Rpb24pCiAgICB7fQp9OwoKdGVtcGxhdGU8dHlwZW5hbWUgRj4Kc3RydWN0IENvbmRpdGlvYW5sQ2FsbDx0cnVlLCBGPgp7CiAgICBDb25kaXRpb2FubENhbGwoRiBmdW5jdGlvbikKICAgIHsKICAgICAgICBhdXRvIGlnbm9yZSA9IGZhbHNlOwogICAgICAgIGZ1bmN0aW9uKGlnbm9yZSk7CiAgICB9Cn07CnRlbXBsYXRlPGJvb2wgQiwgdHlwZW5hbWUgRj4Kdm9pZCBjYWxsQ29uZGl0aW9uYWwoRiYmIGZ1bmN0aW9uKQp7CiAgICBDb25kaXRpb2FubENhbGw8QiwgRj57c3RkOjpmb3J3YXJkPEY+KGZ1bmN0aW9uKX07Cn0KCiNkZWZpbmUgQ09OU1RFWFBSX0lGKGNvbmRpdGlvbiwgYWN0aW9uKSBcCiAgICBjYWxsQ29uZGl0aW9uYWw8Y29uZGl0aW9uPihbJl0oYXV0bykgYWN0aW9uKTsKCgpzdHJ1Y3QgQSAKewogICAgdm9pZCBmb28oKQogICAgewogICAgICAgIHN0ZDo6Y291dCA8PCAiRnJvbSBjbGFzcyBmb28hXG4iOwogICAgfQp9OwoKc3RydWN0IEIge307Cgp2b2lkIGZvbyhCKQp7CiAgICBzdGQ6OmNvdXQgPDwgIkZyb20gc3RhbmRhbG9uZSBmb28hXG4iOwp9CnZvaWQgZm9vKEEpCnsKICAgIHN0ZDo6Y291dCA8PCAiRnJvbSBzdGFuZGFsb25lIGZvbyFcbiI7Cn0KCgppbnQgbWFpbigpCnsKICAgIEEgYTsKICAgIEIgYjsKICAgIENPTlNURVhQUl9JRighSGFzRm9vX3Y8Qj4sIHtmb28oYik7fSk7CiAgICBDT05TVEVYUFJfSUYoSGFzRm9vX3Y8QT4sIHthLmZvbygpO30pOwoKICAgIHJldHVybiAwOwp9