有什么方法可以进行部分专业化?
There is any way to do a partial specialization?
只是为了好玩,我正在尝试使用模板实现编译时 pow2 函数。
实际上,我可以这样做:
template <std::size_t n, typename type_t>
struct custom
{
static type_t pow(type_t b) { return b * custom<n - 1, type_t>::pow(b); }
};
template <typename type_t>
struct custom<0, type_t>
{
// (void)b; to avoid unused warning.
static type_t pow(type_t b) { (void) b; return static_cast<type_t>(1); }
};
这样就可以了,但我的方法是这样想的:
template <std::size_t n, typename type_t>
type_t cus_pow(type_t b) { return b * cus_pow<n - 1, type_t>(b); }
// This doesn't exists.
template <0, typename type_t>
type_t cus_pow(type_t b) { (void) b; return 1; }
因为如果我想创建任何部分元编程函数,就被迫创建一个结构,它看起来太多了。
那么,有什么方法可以只用一个函数进行部分元编程吗?
您不能部分专业化 function/method。
您可以使用 if constexpr
(C++17) 来避免重复:
static type_t pow([[maybe_unused]]type_t b) {
if constexpr (n == 0) {
return static_cast<type_t>(1); }
} else {
return b * custom<n - 1, type_t>::pow(b);
}
}
没有额外的运行时分支。
So, there is any way to do partial metaprogramming just with one function?
否:您不能部分特化模板函数。
但是还有其他方法可以解决这个问题。
如果你可以使用 C++17,一个优雅的解决方案是使用 if constexpr
(参见 Jarod42 的回答)。
在C++17之前,可以使用SFINAE
template <std::size_t n, typename type_t>
std::enable_if_t<n == 0u, type_t> cus_pow (type_t)
{ return 1; }
template <std::size_t n, typename type_t>
std::enable_if_t<n != 0u, type_t> cus_pow (type_t b)
{ return b * cus_pow<n - 1, type_t>(b); }
到 enable/disable 零版本或非零版本,根据 n
的值(并定义(或至少声明)零版本 before, 假设非零版本可以调用它)。
另一种解决方案可以是标签调度
template <std::size_t, typename type_t>
type_t cus_pow (std::true_type, type_t)
{ return 1; }
template <std::size_t n, typename type_t>
type_t cus_pow (std::false_type, type_t b)
{ return b * cus_pow<n-1u, type_t>(std::integral_constant<bool, n-1u==0u>{}, b); }
template <std::size_t n, typename type_t>
type_t cus_pow (type_t b)
{ return cus_pow<n>(std::integral_constant<bool, n==0u>{}, b); }
调用另一个带有“标签”(std::true_type
或 std::false_type
)的函数,说明 n
是否为零。
只是为了好玩,我正在尝试使用模板实现编译时 pow2 函数。 实际上,我可以这样做:
template <std::size_t n, typename type_t>
struct custom
{
static type_t pow(type_t b) { return b * custom<n - 1, type_t>::pow(b); }
};
template <typename type_t>
struct custom<0, type_t>
{
// (void)b; to avoid unused warning.
static type_t pow(type_t b) { (void) b; return static_cast<type_t>(1); }
};
这样就可以了,但我的方法是这样想的:
template <std::size_t n, typename type_t>
type_t cus_pow(type_t b) { return b * cus_pow<n - 1, type_t>(b); }
// This doesn't exists.
template <0, typename type_t>
type_t cus_pow(type_t b) { (void) b; return 1; }
因为如果我想创建任何部分元编程函数,就被迫创建一个结构,它看起来太多了。
那么,有什么方法可以只用一个函数进行部分元编程吗?
您不能部分专业化 function/method。
您可以使用 if constexpr
(C++17) 来避免重复:
static type_t pow([[maybe_unused]]type_t b) {
if constexpr (n == 0) {
return static_cast<type_t>(1); }
} else {
return b * custom<n - 1, type_t>::pow(b);
}
}
没有额外的运行时分支。
So, there is any way to do partial metaprogramming just with one function?
否:您不能部分特化模板函数。
但是还有其他方法可以解决这个问题。
如果你可以使用 C++17,一个优雅的解决方案是使用 if constexpr
(参见 Jarod42 的回答)。
在C++17之前,可以使用SFINAE
template <std::size_t n, typename type_t>
std::enable_if_t<n == 0u, type_t> cus_pow (type_t)
{ return 1; }
template <std::size_t n, typename type_t>
std::enable_if_t<n != 0u, type_t> cus_pow (type_t b)
{ return b * cus_pow<n - 1, type_t>(b); }
到 enable/disable 零版本或非零版本,根据 n
的值(并定义(或至少声明)零版本 before, 假设非零版本可以调用它)。
另一种解决方案可以是标签调度
template <std::size_t, typename type_t>
type_t cus_pow (std::true_type, type_t)
{ return 1; }
template <std::size_t n, typename type_t>
type_t cus_pow (std::false_type, type_t b)
{ return b * cus_pow<n-1u, type_t>(std::integral_constant<bool, n-1u==0u>{}, b); }
template <std::size_t n, typename type_t>
type_t cus_pow (type_t b)
{ return cus_pow<n>(std::integral_constant<bool, n==0u>{}, b); }
调用另一个带有“标签”(std::true_type
或 std::false_type
)的函数,说明 n
是否为零。