我试图创建一个元组模拟以访问其元素与相应的标记类型,而不是索引。我想出了一个解决方案(简化):C++:带标记类型访问的元组
template<class T> struct tag { using type = T; };
using r = tag<double>;
using t = tag<double>;
using c = tag<int>;
template<class... Ts> class S
{
std::tuple<typename Ts::type&&...> data;
public:
S(typename Ts::type&&... args) : data(std::forward<typename Ts::type>(args)...) {}
};
int main()
{
r::type r0 = 0.;
const t::type t0 = 1.;
auto S0 = S<r, t, c>(r0, t0, 2); // <- error here
//auto T0 = std::forward_as_tuple(r0, t0, 2); // <- works!
}
然而,它没有编译器(gcc 7.2):
error: cannot bind rvalue reference of type ‘tag<double>::type&& {aka double&&}’ to lvalue of type ‘tag<double>::type {aka double}’
auto S0 = S<r, t, c>(r0, t0, 2);
^
note: initializing argument 1 of ‘S<Ts>::S(typename Ts::type&& ...) [with Ts = {tag<double>, tag<double>, tag<int>}]’
S(typename Ts::type&&... args) : data(std::forward<typename Ts::type>(args)...) {}
^
我发现std::forward_as_tuple
功能,能够正确地推断参数类型,所以我点是为我的班级做同样的事情。任何暗示我做错了什么?
UPD:初始描述不完整,抱歉。我的意图不是存储副本,而是引用(对于非const参数非const,对于const和rvalue引用const类似于std::forward_as_tuple
)。请参阅下面的更新代码中的注释:
template<class... Ts> class S
{
std::tuple<typename Ts::type...> data;
public:
template<class... Args>
S(Args&&... args) : data(std::forward<Args>(args)...) {}
template<size_t I> auto& get()
{
return std::get<I>(data);
}
};
int main()
{
r::type r0 = 0.;
const t::type t0 = 1.;
auto S0 = S<r, t, c>(r0, t0, 2);
S0.get<0>() = 111; // <- r0 is not changed!
S0.get<1>() = 222; // <- must not be possible!
auto T0 = std::forward_as_tuple(r0, t0, 2);
std::get<0>(T0) = 333; // <- r0 == 333
std::get<1>(T0) = 444; // <- compile error -- can't change const!
}
std :: tuple akready很好玩。 –
'typename Ts :: type &&'实际上是右值引用而不是转发引用。 – Jarod42
@ n.m。不完全 - 我的目标是通过标记类型获取值,而不是索引。标签是可区分的,但实际类型不是 –