My question is simple to ask, but I guess, difficult to answer.
In C++14, is there a way to test if a callable (function, function member, lambda function, std::function etc...) has a side effect or not?
If so, how would a type traits:
template <class T>
struct has_side_effects;
would be like?
I am ok with a trait that would return false positive (says that a function has side effects while it does not), but not ok with a trait that would return false negative (says that a function has no side effects while it does).
For example, I would like the trait:
auto comparator = [](const auto& x, const auto& y){return y > x;};
bool result = std::has_side_effects<decltype(comparator)>::value;
to return false
.
As stated, template<class T> using has_side_effects = std::true_type;
solves most of your problem. Simply state that everything has side effects, and ship it. False positives, but no false negatives!
In general, non-trivial properties of an algorithm coded in a Turing-complete system cannot be computed. Doing so is equivalent to the halting problem. So the problem cannot be solved in general.
In specific cases, C++ offers basically zero reflection over the contents of an algorithm. At best it offers some reflection over the interface of an algorithm, but the interface of an algorithm/function does not contain information about the purity of the algorithm.
The closest you can get is "can it be invoked within a constexpr
context".
In a concrete case:
auto comparator = [](const auto& x, const auto& y){return y > x;};
bool result = std::has_side_effects<decltype(comparator)>::value;
result would have to be true
, as:
struct evil {
static int count() { static int r = 0; return ++r; }
friend bool operator<( evil lhs, evil rhs ) { count(); return false; }
};
then comparator(evil{}, evil{})
has a side effect. Having it return false
when passed comparator
is simply incorrect.