Chr*_* G. 3 c++ tuples variadic-templates constexpr c++20
我想通过constexpr constructor a存储传递的数据struct,并将数据存储在 a 中std::tuple,以执行各种 TMP/编译时操作。
执行
template <typename... _Ts>
struct myInitializer {
std::tuple<_Ts...> init_data;
constexpr myInitializer(_Ts&&... _Vs)
: init_data{ std::tuple(std::forward<_Ts>(_Vs)...) }
{}
};
Run Code Online (Sandbox Code Playgroud)
存储的数据使用轻量级strong type结构,通过左值和右值帮助器重载生成:
template <typename T, typename... Ts>
struct data_of_t {
using type = T;
using data_t = std::tuple<Ts...>;
data_t data;
constexpr data_of_t(Ts&&... _vs)
: data(std::forward<Ts>(_vs)...)
{}
};
template<typename T, typename... Ts>
constexpr auto data_of(Ts&&... _vs) {
return data_of_t<T, Ts...>(std::forward<Ts>(_vs)...);
};
template<typename T, typename... Ts>
constexpr auto data_of(Ts&... _vs) {
return data_of_t<T, Ts...>(std::forward<Ts>(_vs)...);
};
Run Code Online (Sandbox Code Playgroud)
它的实现就像
template <typename T = int>
class test {
public:
static constexpr auto func(int p0=0, int p1=1, int p2=3) noexcept {
return data_of <test<T>>
(data_of<test<T>>(p0, p1));
}
};
Run Code Online (Sandbox Code Playgroud)
int main() {
constexpr // fails to run constexpr // works without
auto init = myInitializer (
test<int>::func()
,test<int>::func(3)
,test<int>::func(4,5)
);
std::apply([&](auto&&... args) {
//std::cout << __PRETTY_FUNCTION__ << std::endl;
auto merged_tuple = std::tuple_cat(std::forward<decltype(args.data)>(args.data)...);
}
, init.init_data);
}
Run Code Online (Sandbox Code Playgroud)
进入正题
如果 myInitializer 实例为 ,则 std::tuple_cat 失败constexpr。
std::apply([&](auto&&... args) {
auto merged_tuple = std::tuple_cat(std::forward<decltype(args.data)>(args.data)...);
Run Code Online (Sandbox Code Playgroud)
const它似乎与通过 添加的限定符有关constexpr。
如何解决这个问题?
这:
auto merged_tuple = std::tuple_cat(std::forward<decltype(args.data)>(args.data)...);
Run Code Online (Sandbox Code Playgroud)
不是转发数据的正确方式。decltype(args.data)将为您提供该数据成员的类型 - 这不是 的常量或值类别的函数args。让我们举一个更简单的例子:
void f(auto&& arg) {
g(std::forward<decltype(arg.data)>(arg.data));
}
struct C { int data; };
C c1{1};
const C c2{2};
f(c1);
f(c2);
f(C{3});
Run Code Online (Sandbox Code Playgroud)
所以这里我有三个调用f(分别调用f<C&>、f<const C&>和f<C>)。在所有这三种情况下,decltype(arg.data)都是...只是int。这就是类型C::data。但这不是它需要转发的方式(它不会编译,c2因为我们试图抛弃 const-ness - 就像你的例子一样 - 并且它会错误地移出c1)。
您想要的是arg单独转发 ,然后访问数据:
void f(auto&& arg) {
g(std::forward<decltype(arg)>(arg).data);
}
Run Code Online (Sandbox Code Playgroud)
现在,decltype(arg)实际上从实例化到实例化都有所不同,这是一个很好的指标,表明我们正在做一些明智的事情。