В общем, я согласен с Богумилом, но позвольте мне сделать дополнительный комментарий. Если у вас есть контроль над тем, как вызывается cat
, вы можете, по крайней мере, написать какой-нибудь код отправки признаков:
struct MyCustomArray{T, N} <: AbstractArray{T, N}
x::Array{T, N}
end
HasCustom() = Val(false)
HasCustom(::MyCustomArray, rest...) = Val(true)
HasCustom(::AbstractArray, rest...) = HasCustom(rest...)
# `IsCustom` or something would be more elegant, but `Val` is quicker for now
Base.cat(::Val{true}, args...; dims) = println("something fancy")
Base.cat(::Val{false}, args...; dims) = cat(args...; dims=dims)
И компилятор достаточно крут, чтобы оптимизировать это:
julia> args = (v, v, w);
julia> @code_warntype cat(HasCustom(args...), args...; dims=2);
Variables
#self#::Core.Compiler.Const(cat, false)
#unused#::Core.Compiler.Const(Val{true}(), false)
args::Tuple{Array{Int64,1},Array{Int64,1},MyCustomArray{Int64,1}}
Body::Nothing
1 ─ %1 = Main.println("something fancy")::Core.Compiler.Const(nothing, false)
└── return %1
Если вы не контролируете вызовы cat
, единственное средство, которое я могу придумать, чтобы заставить вышеуказанный метод работать, - это overdub методы, содержащие такой вызов , чтобы заменить соответствующие вызовы специальной реализацией. В этом случае вам даже не нужно перегружать cat
, но вы можете напрямую заменить его каким-нибудь mycat
, выполняющим ваши модные вещи.