SFINAE 函数,根据模板类型返回正确的字符编码?

SFINAE function that returns proper character encoding depending on template type?

提问人:Tee Mo 提问时间:6/30/2023 更新时间:6/30/2023 访问量:49

问:

我正在创建一个编写代码字符串的类, string 和 wring 之间的区别只是放在basic_string中的内容,所以我打算把它写成一个模板类。

问题在于内部使用的文本字符串也必须根据 Type 进行更改,因此我将宏和 SFINAE 组合在一起,创建了一个函数,该函数根据 Type 返回不同的文本字符串。

但是我的代码有一个“没有函数模板的实例与参数列表匹配”错误。

这是我的代码:

#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;
}

除了手写每个文字字符串之外,没有其他方法吗?

我尝试更改参数类型,但我不熟悉 SFINAE,所以我尝试的所有内容都有错误。

我所期望的是,由于 SFINAE 的特性,输入类型时返回文字“\t”,输入<wchar_t>类型时返回文字 L“\t”。

可能吗?

C++ 字符串 模板 sfinae

评论

0赞 Marek R 6/30/2023
看起来像 XY 问题。下面介绍如何在 MSVC 中处理编码: stackoverflow.com/a/67819605/1387438
1赞 Holt 6/30/2023
@MarekR 这不是编码问题,而是如何根据模板参数更改字符文本类型。当您的模板类格式类似于字符串并使用标准字符(通常是制表符或换行符)时,这是一个非常常见的问题,并且您需要使用正确版本的字符来设置格式。
0赞 Jarod42 6/30/2023
L##str是错误的(是创建标识符)(GCC 拒绝它)。使用(让连接 C 字符串文字)有效。##L"" str

答:

4赞 Holt 6/30/2023 #1

您的用法不正确,一种可能的用法是enable_if

template <typename U = T, std::enable_if_t<std::is_same_v<U, wchar_t>, int> = 0>

目前,您的 SFINAE 重载如下所示Tchar

template <typename U = char, char>

所以很明显,第二个非类型模板参数是无法推导出来的。char


在 C++17 及更高版本中,您可以简单地使用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; }
}

您还可以使用 转换为适当的字符类型。这应该适用于基本字符(尤其是)。std::char_traits<T>::to_char_type('\n')'\n'\n\t