Printing wide characters to narrow streams is not supported and doesn't work at all. (It "works" but the result is not what you want).
Printing multibyte narrow strings to wide streams is not supported and doesn't work at all. (It "works" but the result is not what you want).
On a Unicode-ready system, std::cout << "\u2654" works as expected. So does std::cout << u8"\u2654". Most properly set up Unix-based operating systems are Unicode-ready.
On a Unicode-ready system, std::wcout << L'\u2654' should work as expected if you set up your program locale properly. This is done with this call:
::setlocale(LC_ALL, "");
or this
::std::locale::global(::std::locale(""));
Note "should"; with some compilers/libraries this method may not work at all. It's a deficiency with these compilers/libraries. I'm looking at you, libc++. It may or may not officially be a bug, but I view it as a bug.
You should really set up your locale in all programs that wish to work with Unicode, even if this doesn't appear necessary.
Mixing cout and wcout in the same program does not work and is not supported.
std::wcout << U'\u2654' does not work because this is mixing a wchar_t stream with a char32_t character. wchar_t and char32_t are different types. I guess a properly set up std::basic_stream<char32_t> would work with char32_t strings, bit the standard library doesn't provide any.
char32_t based strings are good for storing and processing Unicode code points. Do not use them for formatted input and output directly. std::wstring_convert can be used to convert them back and forth.
TL;DR work with either std::streams and std::strings, or (if you are not on libc++) std::wstreams and std::wstrings.