【问题标题】:Can I template user-defined literals?我可以模板用户定义的文字吗?
【发布时间】:2017-01-06 13:02:28
【问题描述】:

假设我有一些课程:

template <typename T>
class Foo {
  const T* x_;
public:
  Foo(const T* str) : x_{str} {}
};

我提供了一些创建Foo 对象的用户定义文字:

Foo<char> operator"" _foo(const char* str, std::size_t) {
  return Foo<char>{str};
}

Foo<wchar_t> operator"" _foo(const wchar_t* str, std::size_t) {
  return Foo<wchar_t>{str};
}

// etc. for char16_t and char32_t.

我的问题是:为什么我不能将这些模板化而不必重写代码?

template <typename T>
Foo<T> operator"" _foo(const T* str, std::size_t) {
  return Foo<T>{str};
}

gcc 5.4.0(Ubuntu 5.4.0-6ubuntu1~16.04.4)和7.0.0(自己编译)报告:

error: ‘Foo<T> operator""_foo(const T*, std::size_t)’ has invalid argument list
Foo<T> operator"" _foo(const T* str, std::size_t) {
                                                ^

错误信息似乎很清楚,但我没有看到原则上不允许我这样做的原因;那么,我这样做是不对的,还是真的不允许这样做?

【问题讨论】:

  • 2.14.8/3 建议模板用户定义的运算符文字是有效的。根据 /5,您的代码对我来说似乎是正确的。您的编译器没有将运算符模板专门化为(特别是)用户定义的 string 文字运算符,而且我的模板 fu 不足以确定这是否是一个错误,或查找规则的结果。
  • @LightnessRacesinOrbit 我猜 [over.literal] 在这里更合适。似乎涉及文字运算符 id 的函数模板必须遵守固定声明(或多或少 template &lt;char...&gt; double operator "" _x())。显然不允许使用其他形式。
  • @skypjack:措辞让我建议尝试使用显式实例化。
  • @Zorawar:下面的答案很好。
  • @LightnessRacesinOrbit:我知道 :) 我的意思是:“我不明白为什么原则上 ...”也许考虑添加时不够有用你已经在限制论点了?

标签: c++ c++11 templates user-defined-literals


【解决方案1】:

考虑this

如果字面量操作符是一个模板,它必须有一个空的参数列表,并且只能有一个模板参数,它必须是一个元素类型为char的非类型模板参数包

换句话说,文字运算符模板的声明应该是:

template <char...> double operator "" _x();

那不是你的情况。


我不是语言律师,但我想与您的案例相关的标准部分是 [over.literal](链接到工作草案)。

[over.literal]/2 的摘录如下:

使用literal-operator-id 声明的函数模板是文字运算符模板。

下面[over.literal]/5被引用:

文字运算符模板的声明应具有空的参数声明子句,并且其模板参数列表应具有单个模板参数,该模板参数是非类型模板参数包([temp.variadic])元素类型 char。

在我看来,与问题中的声明类似的声明被标准明确禁止。
更一般地说,声明文字运算符的函数模板必须严格遵守给定的模式。


这是我做错了,还是真的不允许这样做?

我会说这是确实不允许

无论如何,如果您有不想在每个运算符中重复的复杂逻辑,您仍然可以使用模板函数:

template<typename T>
Foo<T> create(const T *str) {
    // your logic...
    return Foo<T>{str};
}

Foo<char> operator"" _foo(const char *str, std::size_t) {
    return create(str);
}

Foo<wchar_t> operator"" _foo(const wchar_t *str, std::size_t) {
    return create(str);
}

这是一个额外的间接层的问题,仅此而已。
显然,如果你所有的操作符都是一行体函数,那是不值得的。

【讨论】:

  • 我想这已经足够清楚了。不过,我想知道他们为什么不允许这样做。也许未来的标准会放宽这一禁令......
  • @Zorawar 我和你一样好奇,但我不知道为什么不允许这样做。对不起。
  • 没关系!感谢您的回答。至少我知道我不只是犯了一个愚蠢的错误!
猜你喜欢
  • 1970-01-01
  • 2021-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-16
  • 1970-01-01
  • 2017-11-26
  • 1970-01-01
相关资源
最近更新 更多