I'm creating a class that's writing code strings, The difference between the string and the wring is only what to put in the basic_string, so I'm going to write it as a template class.
The problem is that the literal strings used internally also have to change depending on the Type, so I combined macro and SFINAE to create a function that returns different literal strings depending on the Type.
But my code had a "no instance of function template matches the argument list" error.
this is my code:
#include <filesystem>
#include <string>
#include <type_traits>
#include <fstream>
#include "windows.h"
namespace stdfs = std::filesystem;
template <typename T>
class CCodeWriter
{
public:
CCodeWriter() {};
~CCodeWriter() {};
private:
template <typename U = T, typename std::enable_if_t<std::is_same_v<U, wchar_t>, wchar_t>>
const std::basic_string_view<U> ConvString(const std::string_view _AstrView, const std::wstring_view _WstrView)
{
return _WstrView;
}
template <typename U = T, typename std::enable_if_t<std::is_same_v<U, char>, char>>
const std::basic_string_view<U> ConvString(const std::string_view _AstrView, const std::wstring_view _WstrView)
{
return _AstrView;
}
#define CONV_STRING(str) ConvString(str, L##str)
private:
int m_iIndentation;
std::basic_ofstream<T> m_ofs;
public:
HRESULT Open(stdfs::path const& _path) { return S_OK; }
bool IsOpen() const { return m_ofs.is_open(); }
void WriteCode(const std::basic_string_view<T> _strCode)
{
...
//Error
m_ofs << CONV_STRING("\t");
//Error
m_ofs << ConvString("\t", L"\t");
...
}
};
int main()
{
CCodeWriter<char> writer;
writer.WriteCode("HI");
return 0;
}
Isn't there any other way but write each literal strings by hand?
I tried to change the parameter type, but I'm not familiar with SFINAE, so everything I've tried has an error.
What I expect is that due to the attibutes of SFINAE, the literal "\t" is returned when the type is entered in , and the literal L"\t" is returned when the <wchar_t> type is entered.
Will it be possible?
Your enable_if
usage is incorrect, one possible usage would be
template <typename U = T, std::enable_if_t<std::is_same_v<U, wchar_t>, int> = 0>
Currently, when T
is char
, your SFINAE overloads looks like this
template <typename U = char, char>
So obviously that second char
non-type template parameter cannot be deduced.
In C++17 and above, you can simply use if constexpr
const std::basic_string_view<T>
ConvString(const std::string_view _AstrView, const std::wstring_view _WstrView)
{
if constexpr (std::is_same_v<T, char>) { return _AstrView; }
else { return _WstrView; }
}
You can also use std::char_traits<T>::to_char_type('\n')
to convert '\n'
to the appropriate character type. This should work for basic characters (\n
and \t
in particular).