#include <iostream>
template <bool FunctionWasInParameters> struct FunctionMarker {
operator bool() const { return FunctionWasInParameters; }
operator int() const { return FunctionWasInParameters; }
};
template <bool... values> struct Or;
template <bool first, bool... values> struct Or<first, values...> {
static constexpr bool value = first || Or<values...>::value;
};
template <> struct Or<> { static constexpr bool value = false; };
template <class T> struct is_FunctionMarker {
static constexpr bool value = false;
};
template <bool B> struct is_FunctionMarker<FunctionMarker<B>> {
static constexpr bool value = true;
};
#define OVERLOAD_OPERATOR_FOR_FUNCTION_MARKER(OPERATOR) \
template <bool B, class T> \
FunctionMarker<B> operator OPERATOR(FunctionMarker<B>, T) { \
return {}; \
} \
template <bool B, class T> \
FunctionMarker<B> operator OPERATOR(T, FunctionMarker<B>) { \
return {}; \
} \
/* to break ambiguity by specialization */ \
template <bool B, bool B2> \
FunctionMarker<B || B2> operator OPERATOR(FunctionMarker<B>, \
FunctionMarker<B2>) { \
return {}; \
}
OVERLOAD_OPERATOR_FOR_FUNCTION_MARKER(|| )
OVERLOAD_OPERATOR_FOR_FUNCTION_MARKER(+)
OVERLOAD_OPERATOR_FOR_FUNCTION_MARKER(*)
// TODO: overload all other operators!
template <class... Args>
auto function(Args... args)
-> FunctionMarker<Or<is_FunctionMarker<Args>::value...>::value> {
return {};
}
FunctionMarker<false> function() { return {}; }
int main() {
int a = function();
int b = function(0);
int c = function(function(0));
int d = function(3 * function(1) + 2);
bool e = function(true || function(1));
// clang-format off
std::cout << a << "//a==false\n"
<< b << "//b==false\n"
<< c << "//c==true\n"
<< d << "//d==true (weakly-typed language)\n"
<< e << "//e==true (strongly-typed language)\n";
}