如何在c++中定义编译时间三元字面字面?

发布于 2025-02-02 16:25:21 字数 2032 浏览 4 评论 0原文

第19章的第4章 c ++编程语言书籍,有一个使用模板技术来定义三元编号的示例,但是该示例没有编译。我试图以对我看上去正确的方式修复它,但仍然没有编译。

#include <cstdint>
#include <iostream>

using namespace std;

constexpr uint64_t ipow(uint64_t x, uint64_t n)
{
  return n > 0 ? x * ipow(x, n - 1) : 1;
}

template <char c>
constexpr uint64_t base3()
{
  static_assert(c >= '0' && c <= '2', "Not a ternary digit.");
  return c - '0';
}

template <char c, char... tail>
constexpr uint64_t base3()
{
  static_assert(c >= '0' && c <= '2', "Not a ternary digit.");
  return ipow(3, sizeof...(tail)) * (c - '0') + base3<tail...>();
}

template <char... chars>
constexpr uint64_t operator""_b3()
{
  return base3<chars...>();
}

int main()
{
  cout << 1000_b3 << endl;
  return 0;
}

clang 给出以下错误:

error: call to 'base3' is ambiguous
  return ipow(3, sizeof...(tail)) * (c - '0') + base3<tail...>();
                                                ^~~~~~~~~~~~~~
<source>:22:49: note: in instantiation of function template specialization 'base3<'0', '0'>' requested here
<source>:22:49: note: in instantiation of function template specialization 'base3<'0', '0', '0'>' requested here
<source>:28:10: note: in instantiation of function template specialization 'base3<'1', '0', '0', '0'>' requested here
  return base3<chars...>();
         ^
<source>:33:15: note: in instantiation of function template specialization 'operator""_b3<'1', '0', '0', '0'>' requested here
  cout << 1000_b3 << endl;
              ^
<source>:12:20: note: candidate function [with c = '0']
constexpr uint64_t base3()
                   ^
<source>:19:20: note: candidate function [with c = '0', tail = <>]
constexpr uint64_t base3()
                   ^
1 error generated.

定义它的正确方法是什么?

In Chapter 19 of the 4th edition of the C++ Programming Language book, there is an example of defining a ternary number literal using a template technique, but the example does not compile. I tried to fix it in the way it looks right to me, but it still does not compile.

#include <cstdint>
#include <iostream>

using namespace std;

constexpr uint64_t ipow(uint64_t x, uint64_t n)
{
  return n > 0 ? x * ipow(x, n - 1) : 1;
}

template <char c>
constexpr uint64_t base3()
{
  static_assert(c >= '0' && c <= '2', "Not a ternary digit.");
  return c - '0';
}

template <char c, char... tail>
constexpr uint64_t base3()
{
  static_assert(c >= '0' && c <= '2', "Not a ternary digit.");
  return ipow(3, sizeof...(tail)) * (c - '0') + base3<tail...>();
}

template <char... chars>
constexpr uint64_t operator""_b3()
{
  return base3<chars...>();
}

int main()
{
  cout << 1000_b3 << endl;
  return 0;
}

Clang gives the following error:

error: call to 'base3' is ambiguous
  return ipow(3, sizeof...(tail)) * (c - '0') + base3<tail...>();
                                                ^~~~~~~~~~~~~~
<source>:22:49: note: in instantiation of function template specialization 'base3<'0', '0'>' requested here
<source>:22:49: note: in instantiation of function template specialization 'base3<'0', '0', '0'>' requested here
<source>:28:10: note: in instantiation of function template specialization 'base3<'1', '0', '0', '0'>' requested here
  return base3<chars...>();
         ^
<source>:33:15: note: in instantiation of function template specialization 'operator""_b3<'1', '0', '0', '0'>' requested here
  cout << 1000_b3 << endl;
              ^
<source>:12:20: note: candidate function [with c = '0']
constexpr uint64_t base3()
                   ^
<source>:19:20: note: candidate function [with c = '0', tail = <>]
constexpr uint64_t base3()
                   ^
1 error generated.

What is the right way to define it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

晒暮凉 2025-02-09 16:25:21

当前,当tail只有1个字符(当用用户定义的文字定义的最后一个数字调用时,它可以调用base3 base3 base3 < /code>

template <char c>
constexpr uint64_t base3()  // With c as '0'
template <char c, char... tail>
constexpr uint64_t base3()  // With c as '0' and tail as an empty parameter pack

没有理由比另一个更喜欢一个,因此这是模棱两可的。

您需要第二个过载以无法完全处理1个参数,因此您可以确保它至少需要2个参数:

template <char c, char second, char... tail>
constexpr uint64_t base3()
{
  static_assert(c >= '0' && c <= '2', "Not a ternary digit.");
  return ipow(3, 1+sizeof...(tail)) * (c - '0') + base3<second, tail...>();
}

或使用Sfinae进行:

template <char c, char... tail>
constexpr
typename std::enable_if<sizeof...(tail) != 0, uint64_t>::type
base3()
{
  static_assert(c >= '0' && c <= '2', "Not a ternary digit.");
  return ipow(3, sizeof...(tail)) * (c - '0') + base3<tail...>();
}

或将其更改为0个字符的基本案例:

template <typename = void>  // Can be called with an empty set of template args
constexpr uint64_t base3()
{
  return 0;
}

template <char c, char... tail>
constexpr uint64_t base3()
{
  static_assert(c >= '0' && c <= '2', "Not a ternary digit.");
  return ipow(3, sizeof...(tail)) * (c - '0') + base3<tail...>();
}

Currently, when tail only has 1 character (when called with the last digit '0' of your user defined literal), it could call either overload of base3

template <char c>
constexpr uint64_t base3()  // With c as '0'
template <char c, char... tail>
constexpr uint64_t base3()  // With c as '0' and tail as an empty parameter pack

There is no reason to prefer one over the other, so it is ambiguous.

You need the second overload to not work with exactly 1 argument, so you can make sure it takes at least 2 arguments:

template <char c, char second, char... tail>
constexpr uint64_t base3()
{
  static_assert(c >= '0' && c <= '2', "Not a ternary digit.");
  return ipow(3, 1+sizeof...(tail)) * (c - '0') + base3<second, tail...>();
}

Or do it with SFINAE:

template <char c, char... tail>
constexpr
typename std::enable_if<sizeof...(tail) != 0, uint64_t>::type
base3()
{
  static_assert(c >= '0' && c <= '2', "Not a ternary digit.");
  return ipow(3, sizeof...(tail)) * (c - '0') + base3<tail...>();
}

Or change it to a base case of 0 characters:

template <typename = void>  // Can be called with an empty set of template args
constexpr uint64_t base3()
{
  return 0;
}

template <char c, char... tail>
constexpr uint64_t base3()
{
  static_assert(c >= '0' && c <= '2', "Not a ternary digit.");
  return ipow(3, sizeof...(tail)) * (c - '0') + base3<tail...>();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文