在C 編程語言書第4版的第 19 章中,有一個使用模板技術定義三進制數文字的示例,但該示例無法編譯。我試圖以我認為正確的方式修復它,但它仍然無法編譯。
#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.
定義它的正確方法是什么?
uj5u.com熱心網友回復:
目前,當tail只有 1 個字符時(使用'0'用戶定義文字的最后一位呼叫時),它可以呼叫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
沒有理由偏愛一個,所以它是模棱兩可的。
您需要第二個多載不能僅使用 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...>();
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/482911.html
上一篇:C 友元函式行為看起來不穩定
