From what I can tell `CClientUIInterface::[signal_name]_disconnect` is a no-op.

In other words calling it does *not* disconnect the slot:

For example `uiInterface.NotifyBlockTip_disconnect(BlockNotifyGenesisWait);` in `AppInitMain(...)` does not disconnect `BlockNotifyGenesisWait` as one would expect. The result being that `BlockNotifyGenesisWait` is invoked for every new block :-)

Running `bitcoind` with some debug printing added shows the issue:

```
[signals] CClientUIInterface::ThreadSafeMessageBox_connect(...) entered with 0 connected slots.
[signals] CClientUIInterface::ThreadSafeMessageBox_connect(...) exited with 1 connected slots.
[signals] CClientUIInterface::ThreadSafeQuestion_connect(...) entered with 0 connected slots.
[signals] CClientUIInterface::ThreadSafeQuestion_connect(...) exited with 1 connected slots.
[signals] CClientUIInterface::InitMessage_connect(...) entered with 0 connected slots.
[signals] CClientUIInterface::InitMessage_connect(...) exited with 1 connected slots.
[signals] CClientUIInterface::InitMessage_connect(...) entered with 1 connected slots.
[signals] CClientUIInterface::InitMessage_connect(...) exited with 2 connected slots.
[signals] Calling uiInterface.NotifyBlockTip_connect(&RPCNotifyBlockChange) in OnRPCStarted()
[signals] CClientUIInterface::NotifyBlockTip_connect(...) entered with 0 connected slots.
[signals] CClientUIInterface::NotifyBlockTip_connect(...) exited with 1 connected slots.
[signals] Calling uiInterface.NotifyBlockTip_connect(BlockNotifyGenesisWait) in AppInitMain(...)
[signals] CClientUIInterface::NotifyBlockTip_connect(...) entered with 1 connected slots.
[signals] CClientUIInterface::NotifyBlockTip_connect(...) exited with 2 connected slots.
[signals] RPCNotifyBlockChange(...) was invoked.
[signals] BlockNotifyGenesisWait(...) was invoked.
[signals] Calling uiInterface.NotifyBlockTip_disconnect(BlockNotifyGenesisWait) in AppInitMain(...)
[signals] CClientUIInterface::NotifyBlockTip_disconnect(...) entered with 2 connected slots.
[signals] CClientUIInterface::NotifyBlockTip_disconnect(...) exited with 2 connected slots.
[signals] RPCNotifyBlockChange(...) was invoked.
[signals] BlockNotifyGenesisWait(...) was invoked.
[signals] RPCNotifyBlockChange(...) was invoked.
[signals] BlockNotifyGenesisWait(...) was invoked.
[signals] RPCNotifyBlockChange(...) was invoked.
[signals] BlockNotifyGenesisWait(...) was invoked.
... and so on ...
```

Note how `BlockNotifyGenesisWait(...)` is called also after `uiInterface.NotifyBlockTip_disconnect(BlockNotifyGenesisWait)`.

I think the problem is that the `disconnect(...)` member function of `boost::signals2::signal` expects a function pointer to be passed in (the same that was passed to `.connect(...)`), but we're doing:

```
void CClientUIInterface::signal_name##_disconnect(std::function<signal_name##Sig> fn)
{
    return g_ui_signals.signal_name.disconnect(&fn);
}
```
{
    uiInterface.NotifyBlockTip_disconnect(&RPCNotifyBlockChange);
    RPCNotifyBlockChange(false, nullptr);
    g_best_block_cv.notify_all();
    LogPrint(BCLog::RPC, "RPC stopped.\n");
}
void SetupServerArgs()
{
    SetupHelpOptions(gArgs);
    gArgs.AddArg("-help-debug", "Print help message with debugging options and exit", false, OptionsCategory::DEBUG_TEST); 
    const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN);
    const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET);
    const auto regtestBaseParams = CreateBaseChainParams(CBaseChainParams::REGTEST);
    const auto defaultChainParams = CreateChainParams(CBaseChainParams::MAIN);
    const auto testnetChainParams = CreateChainParams(CBaseChainParams::TESTNET);
    const auto regtestChainParams = CreateChainParams(CBaseChainParams::REGTEST);
    
    std::vector<std::string> hidden_args = {
        "-dbcrashratio", "-forcecompactdb",
        
        "-allowselfsignedrootcertificates", "-choosedatadir", "-lang=<lang>", "-min", "-resetguisettings", "-rootcertificates=<file>", "-splash", "-uiplatform"};
    gArgs.AddArg("-version", "Print version and exit", false, OptionsCategory::OPTIONS);
    gArgs.AddArg("-alertnotify=<cmd>", "Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)", false, OptionsCategory::OPTIONS);
    gArgs.AddArg("-assumevalid=<hex>", strprintf("If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)", defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnetChainParams->GetConsensus().defaultAssumeValid.GetHex()), false, OptionsCategory::OPTIONS);
    gArgs.AddArg("-blocksdir=<dir>", "Specify blocks directory (default: <datadir>/blocks)", false, OptionsCategory::OPTIONS);
    gArgs.AddArg("-blocknotify=<cmd>", "Execute command when the best block changes (%s in cmd is replaced by block hash)", false, OptionsCategory::OPTIONS);
    gArgs.AddArg("-blockreconstructionextratxn=<n>", strprintf("Extra transactions to keep in memory for compact block reconstructions (default: %u)", DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN), false, OptionsCategory::OPTIONS);
    gArgs.AddArg("-blocksonly", strprintf("Whether to operate in a blocks only mode (default: %u)", DEFAULT_BLOCKSONLY), true, OptionsCategory::OPTIONS);
    gArgs.AddArg("-conf=<file>", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), false, OptionsCategory::OPTIONS);
    gArgs.AddArg("-datadir=<dir>", "Specify data directory", false, OptionsCategory::OPTIONS);