是否可以为字符串文字创建模板化的用户定义字面量(字面量后缀)?

9

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

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: 错误:没有找到与 'operator""_s()' 匹配的函数
std::cout << "123"_s;

prog.cpp:4:34: 注意:候选函数是:模板 std::string operator""_s()
template std::string operator ""_s()

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

(Ideone)

是否有一种方法可以使用模板化的用户定义字面量和字符串字面量?


你想要实现什么?请注意,你也不能使用 << foo_s;,不需要添加引号使其失败。 - Jean-François Fabre
@Jean-FrançoisFabre 我知道。当然这不是一个真正的用例。我想能够根据字符串字面量生成一个唯一的类型,这可能是其中一种可能的方式。 - HolyBlackCat
2个回答

4

Clang和GCC支持一种扩展,允许您进行

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

但是标准的C++中并没有这个功能;已经有多次建议将此功能纳入标准,但每次都被拒绝,最近不到一个月前也是如此,主要原因在于模板参数包是一种非常低效的表示字符串的方式。


谢谢您的回答。但是,如果那么低效,为什么我们会有针对数字字面量的模板化版本呢? - HolyBlackCat
1
@HolyBlackCat 最初的理由是它们在 constexpr 中用于编译时计算非常有用。此外,这些字面量通常很短,并且它们是在没有实现的时候标准化的(因此编译时成本不一定明显)。 - T.C.
7
标准委员会不希望我拥有一个编译时的 C++ 编译器。真是扫兴。 - Yakk - Adam Nevraumont
你能提供这个扩展的任何文档链接吗?它有名字吗? - Eric
2
@eric -Wgnu-string-literal-operator-template - vmrob

2

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接