I basically want to select one of the branches at compile-time but can't figure out how to address the error that shows up.
Here is the code (link):
#include <iostream>
#include <vector>
#include <type_traits>
template <typename charT>
struct Foo
{
using value_type = charT;
std::vector<value_type> vec;
void printVec( std::basic_ostream<charT>& out_stream )
{
out_stream.write( std::data( vec ), std::size( vec ) ).write( "\n", 1 );
}
};
// specialization for char
template <>
void Foo<char>::printVec( std::basic_ostream<char>& out_stream )
{
out_stream.write( std::data( vec ), std::size( vec ) ).write( "\n", 1 );
}
// specialization for wchar_t
template <>
void Foo<wchar_t>::printVec( std::basic_ostream<wchar_t>& out_stream )
{
out_stream.write( std::data( vec ), std::size( vec ) ).write( L"\n", 1 );
}
int main( )
{
using FooChar = Foo<char>;
using FooWideChar = Foo<wchar_t>;
#define IS_CHAR 1
#if IS_CHAR == 1
FooChar foo;
foo.vec.resize( 10, '$' );
#else
FooWideChar foo;
foo.vec.resize( 10, L'#' );
#endif
if constexpr ( std::is_same_v< decltype( foo )::value_type,
decltype( std::cout )::char_type > )
{
foo.printVec( std::cout );
}
else if constexpr ( std::is_same_v< decltype( foo )::value_type,
decltype( std::wcout )::char_type > )
{
foo.printVec( std::wcout ); // this is where the compile error occurs
}
else
{
static_assert( std::is_same_v< decltype( foo )::value_type,
decltype( std::cout )::char_type > ||
std::is_same_v< decltype( foo )::value_type,
decltype( std::wcout )::char_type >,
"character type not supported" );
}
}
The error message:
cannot convert 'std::wostream' {aka 'std::basic_ostream<wchar_t>'} to 'std::basic_ostream<char>&'
The message is self-explanatory however I still don't know how to get around this issue. I guess this problem would not arise if the compiler wouldn't check the syntax of the statement inside the else if
branch. Is there any way to make the above snippet compile?
CodePudding user response:
Lift your if constexpr
logic into a template function:
template <typename charT>
void printIt( Foo<charT>& foo )
{
if constexpr ( std::is_same_v<charT, char> )
foo.printVec( std::cout );
else if constexpr ( std::is_same_v<charT, wchar_t> )
foo.printVec( std::wcout );
else
static_assert( sizeof(charT) == 0, "character type not supported" );
}
Also, note you don't need two definitions of printVec()
for char
. You can simply declare it in the class without a definition:
void printVec( std::basic_ostream<charT>& out_stream );
It should probably be const
, then printIt()
can take const Foo&
.