xCode can't cast from AudioBlock to ProcessContextReplacing

Hello,
as in subject there is problem in xCode with casting from AudioBlock to ProcessContextReplacing.
The problem doesn’t happen on Windows in Visual Studio.

I have object:
dsp::IIR::Filter<float> myFilter;

And my code in processBlock() looks like that:
myFilter.process(dsp::ProcessContextReplacing< float >(dsp::AudioBlock<float>( buffer )));

And I get that error:

No matching conversion for functional-style cast from ‘dsp::AudioBlock< float >’ to ‘dsp::ProcessContextReplacing< float >’

I found the solution and to make it work I need to create variable of AudioBlock like that:

dsp::AudioBlock< float > block { buffer };
myFilter.process(dsp::ProcessContextReplacing< float >(block));

And now it works. But I still can’t understand why I can’t construct AudioBlock in place as an parameter for ProcessContext constructor.

I also wonder if it makes the difference for performance between creating variable of AudioBlock and then pass it as an parameter, or constructing it in place?

Intuition tells me that performance is better when we construct in place, but first of all as you see I can’t do that, but secondly maybe my intuition mislead me and there is no difference?

Hmm… Really nobody knows what’s going on here?

First of all this has nothing to do with Xcode, this is just a core rule of the C++ language.

If some object is passed by non-const reference it’s not allowed to implicitly cast the passed argument. Just think of e.g. this:

void foo (juce::String& s) { s.trimStart(); }

Calling it like this:

foo (" Hello");
foo (juce::String (" Hello));

is not allowed. It must be

juce::String s = " Hello";
foo (s);

The reason is, that whenever a non-const reference is passed, the referenced object can be modified. Modifying an object that has just the temporary lifetime of the function call is totally pointless and would likely be a misusage, the expectation is that the modified instance has be used used after the call so that the modification made sense at all.

On the other hand, const references allow implicit conversion, so

bar (const juce::String& s)
{
    std::cout << s;
}

is allowed to be called like

bar ("Hello");                // implicit string constructor
bar (juce::String ("Hello")); // explicit string constructor

since a const instance always indicate some read-only access.

As the constructor of the juce::dsp::ProcessContextReplacing takes a non-const reference to a juce::dsp::AudioBlock the same rule applies here.

That being said, I would argue that in this specific case, declaring the reference const would actually be the right thing, since the point is to operate on the underlying pointers, so creating a temporary block instance is totally fine here and would not cause any harm. I proposed this quite a while ago, so far the JUCE devs did not seem to be convinced by my arguments :wink: :man_shrugging:

Hello PluginPenguin,
great thanks for your answer.
Of course I know that I can’t pass the object created in place as a non-const reference parameter. I feel stupid that I obliged you to explain me that obvious C++ property.

But it is still strange, that I can do that in Visual Studio on Windows 10. I’ve just checked and the constructor of ProcessContextReplacing looks like that:
ProcessContextReplacing (AudioBlockType& block) noexcept : ioBlock (block) {}

So as you can see block parameter is non-const reference. But I still can call:
myFilter.process(dsp::ProcessContextReplacing< float >(dsp::AudioBlock<float>( buffer )));

The problem I have only in xCode. Isn’t it strange?

Best Regards

It is not strange at all. VS should be giving you a warning during the build that you are using out of bounds behavior. your build should have no warnings. warnings are helpful guideposts so you can verify your intended behavior. then you can put in the work to make the compiler understand you meant to do this. or, as in this case, you would fix the warning with proper code. :slight_smile:

OK, thanks for your advices. So it looks like I need to change “warning” settings in VS.

This compiles on Windows because Visual Studio includes “nonstandard compiler extensions” that add support for features that aren’t actually in the C++ standard, and therefore will not compile on other platforms/compilers.

As CPR mentioned, Visual Studio should emit a warning when this happens, so long as your warning level is set to /W4 or above (Warning Level = “High” in Projucer). You should see something like:

warning C4239: nonstandard extension used: 'argument': conversion from 'TypeA' to 'TypeB&'