【问题标题】:String literal that depends on the template type parameter?取决于模板类型参数的字符串文字?
【发布时间】:2018-02-27 17:26:07
【问题描述】:

我有一个可以解析字符串(日期)的类。我希望能够解析普通字符串和宽字符串:

MyClass x;
x.parse("2018-02-27");
x.parse(L"2018-02-27");

由于解析普通字符串和宽字符串的代码基本相同,所以使用模板是有意义的:

template<typename CharT>
void parse(const CharT *str)
{
    // ...
}

现在,我将使用get_time 函数进行解析。它采用fmt 参数,它的类型为const CharT *,我想为此提供一个字符串文字。它必须是普通或宽字符串文字,具体取决于模板类型参数:

template<typename CharT>
void parse(const CharT *str)
{
    tm date;
    basic_istringstream<CharT> date_stream{str};
    date_stream >> get_time(&date, ("%Y-%m-%d" or L"%Y-%m-%d", but how to choose??) );
    // ...
}

我只对两个模板实例感兴趣:char 和 wchar_t。我尝试使用非类型模板参数,但没有设法得到任何可以编译的东西。

实现函数/模板最优雅的方式是什么?

【问题讨论】:

  • 如果你只想要两种类型,为什么不为每种类型重载函数呢?
  • 我不会(几乎)将我的代码复制粘贴两次视为“优雅”。此外,我还要维护两个功能。
  • 复制:link
  • 我同意重复,但即使是这个问题的第一个答案看起来更好。
  • 另一个潜在的重复:stackoverflow.com/questions/4261673/…

标签: c++ templates


【解决方案1】:

添加一个特征类:

template <typename CharT>
struct format {
    static const CharT* const v;
};

template<> const char* const format<char>::v="%Y-%m-%d";
template<> const wchar_t* const format<wchar_t>::v=L"%Y-%m-%d";

然后用作:

date_stream >> get_time(&date, format<CharT>::v);

如果您有野心,您可以将实际复制的格式合并为 #define(然后在必要时使用标记粘贴将 L 粘贴在前面) - 但实际上,我认为这比它更机械值得。

【讨论】:

  • 这比我(现已删除)的答案更好表达,但是:1)我猜你的意思是static const CharT* v。 2)我认为它应该被声明为static const CharT* const v;(然后相应地定义),以确保特征不被程序修改。
  • @jdehesa:在这两种情况下:是的,绝对!谢谢。
【解决方案2】:

我第一次尝试在其中插入 if constexpr 并不顺利,但变量模板看起来不错:

template <typename CharT>
constexpr CharT const *timeFmt;

template <>
constexpr auto timeFmt<char> = "%Y-%m-%d";

template <>
constexpr auto timeFmt<wchar_t> = L"%Y-%m-%d";

template <typename CharT>
void parse(const CharT *str)
{
    std::tm date;
    std::basic_istringstream<CharT> date_stream{str};
    date_stream >> std::get_time(&date, timeFmt<CharT>);
    // ...
}

为了记录,这是我第一次尝试的丑陋的东西:

template<typename CharT>
void parse(const CharT *str)
{
    std::tm date;
    std::basic_istringstream<CharT> date_stream{str};
    date_stream >> std::get_time(&date, []{
        if constexpr (std::is_same_v<CharT, wchar_t>)
            return L"%Y-%m-%d";
        else
            return "%Y-%m-%d";
    }());
    // ...
}

【讨论】:

  • 如果你 OP 想要使用它,请确保你使用支持 C++17 的编译器。此外,模板化的 timeFmt 可以是 constexpr。
  • @razzorflame 变量模板虽然是 C++14 :)
  • 噢,是的,对不起。我说的是if constexpr ;)
  • 这里一样,不应该首选CharT const * const timeFmt;以避免修改吗?
【解决方案3】:

除了变量模板类模板函数模板也可以:

template<typename T> const T* get_format_str();

然后,charwchar_t 的相应特化:

template<> const char*    get_format_str<char>()    { return "%Y-%m-%d"; }
template<> const wchar_t* get_format_str<wchar_t>() { return L"%Y-%m-%d"; }

在您的parse() 函数模板中将此函数模板用作:

date_stream >> get_time(&date, get_format_str<TChar>());

这种方法的优点是:

  • 它只需要 C++98(对于变量模板,您需要 C++14)。
  • 无法修改指向文字字符串的指针(只能修改函数返回的该指针的副本)。

【讨论】:

    猜你喜欢
    • 2019-03-15
    • 1970-01-01
    • 2015-04-30
    • 1970-01-01
    • 2022-01-09
    • 2011-01-03
    • 2018-04-09
    • 2012-07-02
    • 2011-07-29
    相关资源
    最近更新 更多