import std.traits : isCallable;
template isStronglyPure(F...)
if (F.length == 1 && isCallable!F)
import std.traits : arity, isDelegate, isAssociativeArray, isPointer,
hasAliasing, Parameters, ParameterStorageClassTuple, ReturnType,
ParameterStorageClass, FunctionAttribute, functionAttributes;
alias STC = ParameterStorageClass;
if (!(functionAttributes!F & FunctionAttribute.pure_))
static foreach (i; 0 .. arity!F)
if (is(Parameters!F[i] == immutable))
else if (isRefType!(Parameters!F[i]) || hasAliasing!(Parameters!F[i])
|| ParameterStorageClassTuple!F[i] == STC.ref_
|| ParameterStorageClassTuple!F[i] == STC.out_)
if (!is(ReturnType!F : immutable(ReturnType!F)))
private bool isRefType(T)()
if(is(T == class) || isDelegate!T || isAssociativeArray!T || isPointer!T)
template isStronglyPure(string funcName, T ...)
if (isCallable!(mixin(funcName)))
import std.traits : arity, isDelegate, isAssociativeArray, isPointer,
hasAliasing, Parameters, ParameterStorageClassTuple, ReturnType,
ParameterStorageClass, FunctionAttribute, functionAttributes,
import std.typecons : Tuple;
foreach(t; __traits(getOverloads,
mixin(moduleName!(mixin(funcName))),
if (is(Parameters!t == T))
assert(0, "None of the overloads match the given function argurments!");