for N in (:Kraus, :BitFlip, :PhaseFlip, :PauliChannel, :AmplitudeDamping, :PhaseDamping, :Depolarizing, :TwoQubitDephasing, :TwoQubitDepolarizing, :GeneralizedAmplitudeDamping, :MultiQubitPauliChannel)
    @eval $N(c::Circuit) = throw(ArgumentError("noise applied to a circuit must have targets and arguments."))
end
MultiQubitPauliChannel{N}(c::Circuit) where {N} = throw(ArgumentError("noise applied to a circuit must have targets and arguments."))
(::Type{N})(c::Circuit, args...) where {N<:Noise} = apply_noise!(n_targets(N), n_probabilities(N), N, c, args...)
apply_noise!(::Type{N}, c::Circuit, args...) where {N<:Noise} = apply_noise!(n_targets(N), n_probabilities(N), N, c, args...)
Kraus(c::Circuit, args...) = apply_noise!(Kraus, c, args...)

apply_noise!(::Val{1}, ::Val{1}, ::Type{N}, c::Circuit, arg::IntOrQubit, prob::Float64) where {N<:Noise} = add_instruction!(c, Instruction(N(prob), arg))
apply_noise!(::Val{1}, ::Val{2}, ::Type{N}, c::Circuit, arg::IntOrQubit, prob_a::Float64, prob_b::Float64) where {N<:Noise} = add_instruction!(c, Instruction(N(prob_a, prob_b), arg))
apply_noise!(::Val{1}, ::Val{3}, ::Type{N}, c::Circuit, arg::IntOrQubit, prob_a::Float64, prob_b::Float64, prob_c::Float64) where {N<:Noise} = add_instruction!(c, Instruction(N(prob_a, prob_b, prob_c), arg))
apply_noise!(::Val{1}, ::Val{2}, ::Type{N}, c::Circuit, arg::IntOrQubit, probs::Vector{Float64}) where {N<:Noise} = add_instruction!(c, Instruction(N(probs...), arg))
apply_noise!(::Val{1}, ::Val{3}, ::Type{N}, c::Circuit, arg::IntOrQubit, probs::Vector{Float64}) where {N<:Noise} = add_instruction!(c, Instruction(N(probs...), arg))
apply_noise!(::Val{1}, ::Val{NP}, ::Type{N}, c::Circuit, probs::Vector{Float64}) where {N<:Noise, NP} = (foreach(q->add_instruction!(c, Instruction(N(probs...), q)), qubits(c)); return c)
apply_noise!(::Val{1}, ::Val{NP}, ::Type{N}, c::Circuit, probs::Vararg{Float64}) where {N<:Noise, NP} = (foreach(q->add_instruction!(c, Instruction(N(probs...), q)), qubits(c)); return c)
apply_noise!(::Val{2}, ::Val{1}, ::Type{N}, c::Circuit, targ_a::IntOrQubit, targ_b::Int, prob::Float64) where {N<:Noise} = add_instruction!(c, Instruction(N(prob), [targ_a, targ_b]))
apply_noise!(::Val{2}, ::Val{1}, ::Type{N}, c::Circuit, args...) where {N<:Noise} = add_instruction!(c, Instruction(N(args[end]), args[1:end-1]))
apply_noise!(::Type{Kraus}, c::Circuit, args...) = add_instruction!(c, Instruction(Kraus(args[end]), args[1:end-1]))
