我想定義行為類似于冪函式的模板 a^n
a^n = -1哪里a < 0或n < 0a^0 = 0(所以不完全一樣std::pow)- 除此以外
std::pow
我在定義第 1 點的條件時遇到問題 - 我認為這將是enable_if一些已定義的constexpr檢查整數是否為負的組合。
我為 1. 點寫的內容(在下面注釋)可能沒有意義,因為它無法編譯。我只是從元編程開始,老實說我不太了解它。如果您能提供解釋和/或在進入該主題時發現有用的一些資源,我將不勝感激。
#include <iostream>
#include <cmath>
// std::pow
template <int a, int n>
struct hc {
enum { v = a * hc<a, n - 1>::v };
};
// to break recursion from getting to a^0=0
template <int a>
struct hc<a, 1> {
enum { v = a };
};
// a^0 = 0
template <int a>
struct hc<a, 0> {
enum { v = 0 };
};
// a^n=-1 for negative a or n
/*
template <int i>
constexpr bool is_negative = i < 0;
// a ^ n = -1, where a < 0 or n < 0
template <int a, int n,
typename std::enable_if<is_negative<a> || is_negative<n>>::type>
struct hc {
enum { v = -1 };
};
*/
int main() {
// a^0=0
std::cout << hc<0, 0>::v << " -> 0^0=0\n";
std::cout << hc<3, 0>::v << " -> 3^0=0\n";
// a^n=std::pow
std::cout << hc<1, 1>::v << " -> 1^1=" << std::pow(1, 1) << '\n';
std::cout << hc<2, 2>::v << " -> 2^2=" << std::pow(2, 2) << '\n';
std::cout << hc<0, 2>::v << " -> 0^2=" << std::pow(0, 2) << '\n';
std::cout << hc<3, 2>::v << " -> 3^2=" << std::pow(3, 2) << '\n';
std::cout << hc<3, 7>::v << " -> 3^7=" << std::pow(3, 7) << '\n';
// a^n=-1 for negative a or n
std::cout << hc<-3, 7>::v << " -> -3^7=-1\n";
std::cout << hc<3, -7>::v << " -> 3^-7=-1\n";
std::cout << hc<0, -7>::v << " -> 0^7=-1\n";
std::cout << hc<-3, 0>::v << " -> -3^0=-1\n";
}
uj5u.com熱心網友回復:
有幾種方式
更簡單的 IMO,將是 constexpr 函式
constexpr int hc_impl(int a, int n)
{
if (a < 0 || n < 0) return -1;
if (n == 0) return 0;
int res = 1;
for (int i = 0; i != n; n) {
res *= a;
}
return res;
};
template <int a, int n>
struct hc
{
constexpr int v = hc_impl(a, n);
};
使用 struct 的舊方法,您可能會為調度添加一個額外的引數,例如:
template <int a, int n, bool b = (a < 0 || n < 0)>
struct hc;
template <int a, int n>
struct hc<a, n, true> {
enum { v = -1 };
};
template <int a>
struct hc<a, 1, true> {
enum { v = -1 };
};
template <int a>
struct hc<a, 0, true> {
enum { v = -1 };
};
template <int a, int n>
struct hc<a, n, false> {
enum { v = a * hc<a, n - 1>::v };
};
// to break recursion from getting to a^0=0
template <int a>
struct hc<a, 1, false> {
enum { v = a };
};
// a^0 = 0
template <int a>
struct hc<a, 0, false> {
enum { v = 0 };
};
uj5u.com熱心網友回復:
這就是我將如何使用模板 constexpr 做到這一點:
template<int a, int n>
constexpr int pow()
{
if ((a < 0) || (n < 0)) return -1;
if (n == 0) return 0;
int result = 1;
for (int i = 0; i < n; i ) result *= a;
return result;
}
int main()
{
static_assert(pow<0,0>() == 0);
static_assert(pow<2, 0>() == 0);
static_assert(pow<-1, 0>() == -1);
static_assert(pow<1, -1>() == -1);
static_assert(pow<2, 3>() == 8);
}
uj5u.com熱心網友回復:
您對最后一種情況的部分專業化語法不正確:您應該<>在template<.....> struct hn.
所以,這樣的事情幾乎可以作業:
// a ^ n = -1, where a < 0 or n < 0
template <int a, int n,
typename std::enable_if<is_negative<a> || is_negative<n>>::type>
struct hc<a, n> {
enum { v = -1 };
};
enable_if::type是一種型別,您必須將其置于可以 SFINAE 的位置,而不僅僅是內部的某個位置template<>。您通常將它放在函式簽名或部分模板特化中。
像這樣:
// You have to change your general case definition.
// std::pow
template<int a, int n, typename /*DummyUnusedType*/ = void>
struct hc {
enum { v = a * hc<a, n - 1>::v };
};
// ... your existing definitions here ...
// a ^ n = -1, where a < 0 or n < 0
template <int a, int n>
struct hc<a, n, typename std::enable_if<is_negative<a> || is_negative<n>>::type> {
enum { v = -1 };
};
你實際上甚至不需要is_negativeand typename:
struct hc<a, n, std::enable_if_t<(a < 0 || n < 0)>> { // Parens are optional
唯一剩下的問題是您的<a, 0>案例與負as 的案例相交。您可以a使用相同的技巧將其限制為非負數。
但總的來說,constexpr正如其他答案所建議的那樣,功能更優越。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/364606.html
上一篇:|=在C 中有什么作用?[復制]
