constexpr 模板参数的显式指定参数无效
Invalid explicitly-specified argument for template parameter which is constexpr
我有一个 static_loop
这样的结构
template <std::size_t n, typename F> void static_loop(F&& f) {
static_assert(n <= 8 && "static loop size should <= 8");
if constexpr (n >= 8)
f(std::integral_constant<size_t, n - 8>());
if constexpr (n >= 7)
f(std::integral_constant<size_t, n - 7>());
if constexpr (n >= 6)
f(std::integral_constant<size_t, n - 6>());
if constexpr (n >= 5)
f(std::integral_constant<size_t, n - 5>());
if constexpr (n >= 4)
f(std::integral_constant<size_t, n - 4>());
if constexpr (n >= 3)
f(std::integral_constant<size_t, n - 3>());
if constexpr (n >= 2)
f(std::integral_constant<size_t, n - 2>());
if constexpr (n >= 1)
f(std::integral_constant<size_t, n - 1>());
}
template <typename T> constexpr size_t tupleSize(T) { return tuple_size_v<T>; }
struct A {
int a;
int b;
void run() {
auto ab = std::make_tuple(std::ref(a), std::ref(b));
static_loop<tupleSize(ab)>([&](auto i) { std::get<i>(ab) = i; });
std::cout << a << " " << b << std::endl;
}
};
但是,它无法迭代上面列出的元组。
建议:试试
// .........VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
static_loop<std::tuple_size_v<decltype(ab)>>([&](auto i) { std::get<i>(ab) = i; });
我的意思是...您不能在常量表达式中使用 ab
(作为值),因为 ab
未定义 constexpr
.
而且你不能定义它 constexpr
因为它是使用 std::ref()
初始化的,而不是 constexpr
.
但是您对 ab
作为获取其类型大小的值不感兴趣;您只对 ab
类型感兴趣;这样你就可以通过 decltype(ab)
.
-- 编辑--
题外话建议。
您可以使用基于std::index_sequence
(和模板折叠,从 C++17 开始可用)的经典方法,而不是 static_loop()
。
我的意思是...如果你定义一个 run_1()
函数(使用 run_1_helper()
辅助函数)如下
template <typename F, typename ... Ts, std::size_t ... Is>
void run_1_helper (F const & f, std::tuple<Ts...> & t, std::index_sequence<Is...> const)
{ (f(std::get<Is>(t), Is), ...); }
template <typename F, typename ... Ts>
void run_1 (F const & f, std::tuple<Ts...> & t)
{ run_1_helper(f, t, std::index_sequence_for<Ts...>{}); }
可以这样写A
struct A {
int a;
int b;
void run() {
auto ab = std::make_tuple(std::ref(a), std::ref(b));
run_1([](auto & v, auto i){ v = i; }, ab);
std::cout << a << " " << b << std::endl;
}
};
或者,也许更好,简单地使用std::apply()
,如下
struct A {
int a;
int b;
void run() {
auto ab = std::make_tuple(std::ref(a), std::ref(b));
int i { -1 };
std::apply([&](auto & ... vs){ ((vs = ++i), ...); }, ab);
std::cout << a << " " << b << std::endl;
}
};
改变
template <typename T>
constexpr size_t tupleSize(T) { return tuple_size_v<T>; }
至:
template <typename T>
constexpr size_t tupleSize(T const&) { return tuple_size_v<T>; }
也就是说,通过对 const 的引用而不是值来获取参数。按原样,您正试图在常量表达式中复制一个非 constexpr 元组——这是行不通的。通过引用很好,因为您实际上并没有阅读元组。
我有一个 static_loop
这样的结构
template <std::size_t n, typename F> void static_loop(F&& f) {
static_assert(n <= 8 && "static loop size should <= 8");
if constexpr (n >= 8)
f(std::integral_constant<size_t, n - 8>());
if constexpr (n >= 7)
f(std::integral_constant<size_t, n - 7>());
if constexpr (n >= 6)
f(std::integral_constant<size_t, n - 6>());
if constexpr (n >= 5)
f(std::integral_constant<size_t, n - 5>());
if constexpr (n >= 4)
f(std::integral_constant<size_t, n - 4>());
if constexpr (n >= 3)
f(std::integral_constant<size_t, n - 3>());
if constexpr (n >= 2)
f(std::integral_constant<size_t, n - 2>());
if constexpr (n >= 1)
f(std::integral_constant<size_t, n - 1>());
}
template <typename T> constexpr size_t tupleSize(T) { return tuple_size_v<T>; }
struct A {
int a;
int b;
void run() {
auto ab = std::make_tuple(std::ref(a), std::ref(b));
static_loop<tupleSize(ab)>([&](auto i) { std::get<i>(ab) = i; });
std::cout << a << " " << b << std::endl;
}
};
但是,它无法迭代上面列出的元组。
建议:试试
// .........VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
static_loop<std::tuple_size_v<decltype(ab)>>([&](auto i) { std::get<i>(ab) = i; });
我的意思是...您不能在常量表达式中使用 ab
(作为值),因为 ab
未定义 constexpr
.
而且你不能定义它 constexpr
因为它是使用 std::ref()
初始化的,而不是 constexpr
.
但是您对 ab
作为获取其类型大小的值不感兴趣;您只对 ab
类型感兴趣;这样你就可以通过 decltype(ab)
.
-- 编辑--
题外话建议。
您可以使用基于std::index_sequence
(和模板折叠,从 C++17 开始可用)的经典方法,而不是 static_loop()
。
我的意思是...如果你定义一个 run_1()
函数(使用 run_1_helper()
辅助函数)如下
template <typename F, typename ... Ts, std::size_t ... Is>
void run_1_helper (F const & f, std::tuple<Ts...> & t, std::index_sequence<Is...> const)
{ (f(std::get<Is>(t), Is), ...); }
template <typename F, typename ... Ts>
void run_1 (F const & f, std::tuple<Ts...> & t)
{ run_1_helper(f, t, std::index_sequence_for<Ts...>{}); }
可以这样写A
struct A {
int a;
int b;
void run() {
auto ab = std::make_tuple(std::ref(a), std::ref(b));
run_1([](auto & v, auto i){ v = i; }, ab);
std::cout << a << " " << b << std::endl;
}
};
或者,也许更好,简单地使用std::apply()
,如下
struct A {
int a;
int b;
void run() {
auto ab = std::make_tuple(std::ref(a), std::ref(b));
int i { -1 };
std::apply([&](auto & ... vs){ ((vs = ++i), ...); }, ab);
std::cout << a << " " << b << std::endl;
}
};
改变
template <typename T>
constexpr size_t tupleSize(T) { return tuple_size_v<T>; }
至:
template <typename T>
constexpr size_t tupleSize(T const&) { return tuple_size_v<T>; }
也就是说,通过对 const 的引用而不是值来获取参数。按原样,您正试图在常量表达式中复制一个非 constexpr 元组——这是行不通的。通过引用很好,因为您实际上并没有阅读元组。