【问题标题】:Is it possible to create templated user-defined literals (literal suffixes) for string literals?是否可以为字符串文字创建模板用户定义文字(文字后缀)?
【发布时间】:2017-04-16 15:39:28
【问题描述】:

当我发现可以将用户定义的文字模板化时,我感到很惊讶:

template <char ...C> std::string operator ""_s()
{
    char arr[]{C...};
    return arr;
}

// ...

std::cout << 123_s;

但上述声明不适用于字符串文字:

"123"_s

给我以下错误:

prog.cpp: 在函数 'int main()' 中:
prog.cpp:12:15: 错误:没有匹配函数调用 '运算符""_s()'
std::cout

prog.cpp:4:34: 注意:候选:模板 std::string 运算符""_s()
模板 std::string 运算符 ""_s()

prog.cpp:4:34: 注意:模板参数推导/替换失败:

(Ideone)

有没有办法将模板化的用户定义文字也与字符串文字一起使用?

【问题讨论】:

  • 你想达到什么目的?请注意,您也不能这样做 &lt;&lt; foo_s;,不需要引号使其失败。
  • @Jean-FrançoisFabre 我知道。当然,这不是一个真正的用例。我希望能够基于字符串文字生成唯一类型,这可能是一种可能的方式。

标签: c++ c++11 templates


【解决方案1】:

Clang 和 GCC 支持一个允许你做的扩展

template<class CharT, CharT... Cs>
std::string operator ""_s() { return {Cs...}; }

但标准 C++ 中没有任何内容;对此标准化的提议已经提出了好几次,但每次都被拒绝,最近一次是不到一个月前,主要是因为模板参数包是一种真的低效的表示字符串的方式。

【讨论】:

  • 感谢您的回答。但就是这么低效,那我们为什么还要有数字文字的模板化版本呢?
  • @HolyBlackCat 最初的理由是它们与constexpr 一起用于编译时计算。此外,这些文字通常很短,并且在没有实现的时候被标准化(因此编译时成本不一定很明显),这并没有什么坏处。
  • 标准委员会不希望我有一个编译时 C++ 编译器。剧透运动。
  • 你能链接到这个扩展的任何文档吗?它有名字吗?
  • @eric -Wgnu-string-literal-operator-template
【解决方案2】:

Pre-C++20 在标准 C++ 中是不可能的。请参阅@T.C.'s answer 了解适用于 GCC 和 Clang 的非标准解决方案。


从 C++20 开始,您可以将字符串文字作为模板参数传递。你需要一个像这样的辅助类:

#include <algorithm>
#include <cstddef>
#include <string_view>

namespace impl
{
    // Does nothing, but causes an error if called from a `consteval` function.
    inline void ExpectedNullTerminatedArray() {}
}

// A string that can be used as a template parameter.
template <std::size_t N>
struct ConstString
{
    char str[N]{};

    static constexpr std::size_t size = N - 1;

    [[nodiscard]] std::string_view view() const
    {
        return {str, str + size};
    }

    consteval ConstString() {}
    consteval ConstString(const char (&new_str)[N])
    {
        if (new_str[N-1] != '\0')
            impl::ExpectedNullTerminatedArray();
        std::copy_n(new_str, size, str);
    }
};

它允许你这样做:

#include <iostream>

template <ConstString S>
void Print()
{
    std::cout << S.view() << '\n';
}

int main()
{
    Print<"foo">();
}

这对于您的用例来说可能已经足够了,而且您本身可能不需要模板 UDL。

但如果你确实需要它们,它是可能的:

#include <iostream>

template <ConstString S>
void operator""_print()
{
    std::cout << S.view();
}

int main()
{
    "foo"_print;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-06
    • 1970-01-01
    相关资源
    最近更新 更多