强制表达式为 constexpr
Force expression to constexpr
给定两个 constexpr
功能,是否可以将它们合并为一个功能?
template <char... C>
constexpr int boo()
{
char ch[] = { C... };
int count = 0;
for (char c : ch)
{
if (c != '0') count += 1;
}
return count;
}
template <char... C>
constexpr auto foo()
{
std::array<char, boo<C...>()> x{};
return x;
}
如示例所示,我可以将 return 'count
' 作为常量。
我的问题是我不能在声明的函数中使用“count
”作为常量。也就是说,如果“boo()
”的主体放在“foo()
”中,编译器会抛出“count
”不是常量。
问题是 std::array
需要一个常量作为大小值。
如果你定义count
并在foo()
中修改它,count
(如foo()
函数中所见)是一个变量,而不是常量。
所以你需要在另一个地方修改它:在一个constexpr
函数中,所以返回值变成一个compile-time已知常量。
如果你可以使用 C++17,那么模板折叠(通过 Evg 和 Rakete1111 的改进;谢谢),你完全可以避免 bar()
template <char... C>
constexpr auto foo()
{
std::array<char, (0u + ... + (C != '0'))> x{};
return x;
}
但是如果你只有 C++11,你需要递归
template <typename = void>
constexpr std::size_t bar ()
{ return 0u; }
template <char C0, char ... C>
constexpr std::size_t bar ()
{ return bar<C...>() + (C0 == '0' ? 0u : 1u); }
template <char... C>
constexpr std::array<char, bar<C...>()> foo()
{ return {}; }
对于 C++14 及更高版本,如果您的目标是 "merge" 主体,您可以简单地在函数模板中定义一个类型:
template <char... C>
constexpr auto foo()
{
struct {
constexpr int operator()() {
char ch[] = { C... };
int count = 0;
for (char c : ch)
{
if (c != '0') count += 1;
}
return count;
};
} boo;
std::array<char, boo()> x{};
return x;
}
如果你有C++17,你也可以在常量表达式中使用lambdas,所以你可以将boo
缩短为:
constexpr auto boo = []() { /* ... */ };
在 C++20 中,您将能够直接将 lambda 表达式编写为模板参数,因此您可以进一步简化为(如果您真的想要它):
std::array<char, []() { /* ... */ }()> x{};
话虽如此,总的来说,我会说通常的(更简洁的)方法是在 header 中使用模板使用的各种额外代码,但这些代码不属于 public 接口将它们放在 detail
或类似命名的命名空间中:
namespace detail {
template <char... C>
constexpr int boo()
{
/* ... */
}
}
template <char... C>
constexpr auto foo()
{
/* ... detail::boo<C...>() ... */
}
给定两个 constexpr
功能,是否可以将它们合并为一个功能?
template <char... C>
constexpr int boo()
{
char ch[] = { C... };
int count = 0;
for (char c : ch)
{
if (c != '0') count += 1;
}
return count;
}
template <char... C>
constexpr auto foo()
{
std::array<char, boo<C...>()> x{};
return x;
}
如示例所示,我可以将 return 'count
' 作为常量。
我的问题是我不能在声明的函数中使用“count
”作为常量。也就是说,如果“boo()
”的主体放在“foo()
”中,编译器会抛出“count
”不是常量。
问题是 std::array
需要一个常量作为大小值。
如果你定义count
并在foo()
中修改它,count
(如foo()
函数中所见)是一个变量,而不是常量。
所以你需要在另一个地方修改它:在一个constexpr
函数中,所以返回值变成一个compile-time已知常量。
如果你可以使用 C++17,那么模板折叠(通过 Evg 和 Rakete1111 的改进;谢谢),你完全可以避免 bar()
template <char... C>
constexpr auto foo()
{
std::array<char, (0u + ... + (C != '0'))> x{};
return x;
}
但是如果你只有 C++11,你需要递归
template <typename = void>
constexpr std::size_t bar ()
{ return 0u; }
template <char C0, char ... C>
constexpr std::size_t bar ()
{ return bar<C...>() + (C0 == '0' ? 0u : 1u); }
template <char... C>
constexpr std::array<char, bar<C...>()> foo()
{ return {}; }
对于 C++14 及更高版本,如果您的目标是 "merge" 主体,您可以简单地在函数模板中定义一个类型:
template <char... C>
constexpr auto foo()
{
struct {
constexpr int operator()() {
char ch[] = { C... };
int count = 0;
for (char c : ch)
{
if (c != '0') count += 1;
}
return count;
};
} boo;
std::array<char, boo()> x{};
return x;
}
如果你有C++17,你也可以在常量表达式中使用lambdas,所以你可以将boo
缩短为:
constexpr auto boo = []() { /* ... */ };
在 C++20 中,您将能够直接将 lambda 表达式编写为模板参数,因此您可以进一步简化为(如果您真的想要它):
std::array<char, []() { /* ... */ }()> x{};
话虽如此,总的来说,我会说通常的(更简洁的)方法是在 header 中使用模板使用的各种额外代码,但这些代码不属于 public 接口将它们放在 detail
或类似命名的命名空间中:
namespace detail {
template <char... C>
constexpr int boo()
{
/* ... */
}
}
template <char... C>
constexpr auto foo()
{
/* ... detail::boo<C...>() ... */
}