如何创建一个`countl_zero()`函数,但适用于任何类型?

huangapple go评论99阅读模式
英文:

How to make a countl_zero() but for any type?

问题

template <typename T>
consteval int CountLeadingZeros(const T& DATA) {
    T MASK{ 1 };
    int BITSN{ sizeof(T) * CHAR_BIT },
        LEADINGN{ 0 };
    MASK <<= BITSN - 1;
    for (int I = BITSN; I > 0; --I, ++LEADINGN, MASK >>= 1) {
        if (DATA & MASK) {
            break;
        }
    }
    return LEADINGN;
}
constexpr int value = CountLeadingZeros<const int>(100);

错误:

E3133 调用到 consteval 函数"fsm::CountLeadingZeros(const T &DATA) [with T=const int]"未生成有效的常量表达式

另一方面,C++20的countl_zero()函数完美工作并返回constexpr。但它只能用于uint8_t以外的类型。

请帮助我解决这个E3133错误。我如何让我的函数在编译时工作?

英文:

I use in my project such a function for counting leading zeros, the aim for it is to work with any non container type and to return a constant expression, so that I could use it's results for other templates.

template &lt;typename T&gt;
consteval int CountLeadingZeros(const T&amp; DATA) {
	T MASK{ 1 };
	int BITSN{ sizeof(T) * CHAR_BIT },
		LEADINGN{ 0 };
	MASK &lt;&lt;= BITSN - 1;
	for (int I = BITSN; I &gt; 0; I--, LEADINGN++, MASK &gt;&gt;= 1) {
		if (DATA &amp; MASK) {
			break;
		}
	}
	return LEADINGN;
}

But of cause it doesn't return a real const expression.
If you'll try to use it, there will be an error:

	constexpr int value = CountLeadingZeros &lt;const int&gt; (100);

Error:

E3133 call to consteval function &quot;fsm::CountLeadingZeros(const T &amp;DATA) [with T=const int]&quot; did not produce a valid constant expression

On the other hand C++20 countl_zero() works perfect and returns constexpr. But it can not work with anything except uint8_t.

Help me please to fight and win this E3133 error. How could I make my function working in compile time?

答案1

得分: 0

不要将const int作为模板参数传递。将其替换为int。目前,MASK被声明为const int MASK = 1,然后您尝试修改它,这显然是行不通的。否则,函数应该是常量可求值的。

英文:

Don't pass const int as the template argument. Replace it with just int. Currently, MASK gets declared as const int MASK = 1, and then you try to modify it, which obviously doesn't work. Otherwise, the function should be constant-evaluatable

答案2

得分: 0

以下是翻译好的代码部分:

一个更多的解决方案:

template <typename T, typename MASK_TYPE = typename remove_const<T>::type>
constexpr int CountLeadingZeros(const T & DATA) {
    MASK_TYPE MASK{ 1 };
    int BITSN{ sizeof(T) * CHAR_BIT },
        LEADINGN{ 0 };
    MASK <<= BITSN - 1;
    for (int I = BITSN; I > 0; I--, LEADINGN++, MASK >>= 1) {
        if (DATA & MASK) {
            break;
        }
    }
    return LEADINGN;
}

或者更简短的版本:

template <typename T, typename MASK_TYPE = typename remove_const<T>::type>
constexpr int LeadingN(const T& DATA) {  // 返回位表示中前导零的数量
    int BITSN{ sizeof(T) * CHAR_BIT }, I{ BITSN };
    MASK_TYPE MASK{ 1u << BITSN - 1 };
    for (; I && !(DATA & MASK); I--, MASK >>= 1) {}
    return BITSN - I;
}

这是结果:
https://github.com/redmms/FineStream/tree/master
英文:

One more solution:

template &lt;typename T, typename MASK_TYPE = typename remove_const&lt;T&gt;::type&gt;
constexpr int CountLeadingZeros(const T &amp; DATA) {
	MASK_TYPE MASK{ 1 };
	int BITSN{ sizeof(T) * CHAR_BIT},
		LEADINGN{ 0 };
	MASK &lt;&lt;= BITSN - 1;
	for (int I = BITSN; I &gt; 0; I--, LEADINGN++, MASK &gt;&gt;= 1) {
		if (DATA &amp; MASK) {
			break;
		}
	}
	return LEADINGN;
}

Or shorter version:

template &lt;typename T, typename MASK_TYPE = typename remove_const&lt;T&gt;::type&gt;
constexpr int LeadingN(const T&amp; DATA) {  // returns number of leading zeros in a bit representation
	int BITSN{ sizeof(T) * CHAR_BIT }, I{ BITSN };
	MASK_TYPE MASK{ 1u &lt;&lt; BITSN - 1 };
	for (; I &amp;&amp; !(DATA &amp; MASK); I--, MASK &gt;&gt;= 1) {}
	return BITSN - I;
}

Here's the result:
https://github.com/redmms/FineStream/tree/master

huangapple
  • 本文由 发表于 2023年7月20日 19:34:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/76729428.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定