从 std::tuple 派生时出现混淆,无法处理 std::get
Confusion while deriving from std::tuple, can not handle std::get
我的基本想法是从 std::tuple 派生出我自己的 class 来获得一些辅助类型,如下所示:
template <typename ... T>
class TypeContainer: public std::tuple<T...>
{
public:
using BaseType = std::tuple<T...>;
static const size_t Size = sizeof...(T);
TypeContainer(T... args):std::tuple<T...>(args...){};
using index_sequence = std::index_sequence_for<T...>;
};
现在我尝试使用代码如下:
using MyType_tuple_with_empty = std::tuple< std::tuple<float,int>, std::tuple<>, std::tuple<int>>;
using MyType_typecontainer_with_empty = TypeContainer< TypeContainer<float,int>, TypeContainer<>, TypeContainer<int>>;
using MyType_tuple_non_empty = std::tuple< std::tuple<float,int>, std::tuple<int>, std::tuple<int>>;
using MyType_typecontainer_non_empty = TypeContainer< TypeContainer<float,int>, TypeContainer<int>, TypeContainer<int>>;
template <typename T>
void Do( const T& parms )
{
// The following lines result in errors if TypeContainer with
// empty element comes in. The empty element is in std::get<1> which
// is NOT accessed here!
std::cout << std::get<0>(std::get<0>(parms)) << " ";
std::cout << std::get<1>(std::get<0>(parms)) << std::endl;
std::cout << std::get<0>(std::get<2>(parms)) << std::endl;
}
int main()
{
MyType_tuple_with_empty p1{{ 1.2,3},{},{1}};
Do( p1 );
MyType_typecontainer_with_empty p2{{ 1.2,3},{},{1}};
Do( p2 ); // << this line raise the error
MyType_tuple_non_empty p3{{ 1.2,3},{4},{1}};
Do( p3 );
MyType_typecontainer_non_empty p4{{ 1.2,3},{4},{1}};
Do( p4 );
}
如果我用 Do(p2)
编译,我会得到以下错误:
error: no matching function for call to 'get(const TypeContainer<TypeContainer<float, int>, TypeContainer<>, TypeContainer<int> >&)
'
有人可以解释为什么与 std::get
相关的空 TypeContainer
的存在会导致该问题吗?
编辑:
附加信息:
线条
MyType_tuple_with_empty p1{{{ 1.2,3},{},{1}}};
MyType_tuple_non_empty p3{{ 1.2,3},{4},{1}};
gcc5.2.0 不能编译,gcc6.1.0 不能编译。这有点神秘,因为我记得元组的构造函数确实是显式的。为什么这适用于 gcc6.1.0?但这不是我搜索的问题:-)
另一个提示:
我遇到问题的代码似乎是用 clang3.5.0 编译的。
有点难懂...
编辑2:
挖掘错误列表(很长一个:-))我发现:
/opt/linux-gnu_5.2.0/include/c++/5.2.0/tuple|832 col 5| note: template argument deduction/substitution failed:
main.cpp|104 col 45| note: 'std::tuple<_Elements ...>
' is an ambiguous base class of 'TypeContainer<TypeContainer<float, int>, TypeContainer<>, TypeContainer<int> >
'
|| std::cout << std::get<0>(std::get<0>(parms)) << " "
;
似乎在 libg++ 中有人多次从任何似乎是损坏的库的元组类型派生。搜索此主题会将我带到:Empty nested tuples error
这真的有关系吗?相同错误或新错误:-)
很遗憾,您必须添加 get 函数的容器版本:
template <std::size_t I, typename ...T>
decltype(auto) get(TypeContainer<T...>&& v)
{
return std::get<I>(static_cast<std::tuple<T...>&&>(v));
}
template <std::size_t I, typename ...T>
decltype(auto) get(TypeContainer<T...>& v)
{
return std::get<I>(static_cast<std::tuple<T...>&>(v));
}
template <std::size_t I, typename ...T>
decltype(auto) get(TypeContainer<T...> const& v)
{
return std::get<I>(static_cast<std::tuple<T...> const&>(v));
}
并且在 Do
类函数中只使用 get
而不是 std::get
。编译器能够从参数中 select 命名空间。
我猜,我不确定,这是因为 gcc 有 EBO - Empty Base Optimization - implemented in its tuples. What are exact reason it is quite hard to guess. You might consider to report this in gcc bugzilla.
顺便说一句,从STD 类 衍生出来不是好习惯。如果您从组合而不是继承开始,那么您将需要提供自己的 get
函数并且您不会观察到此错误,可能会节省很多时间。
我的基本想法是从 std::tuple 派生出我自己的 class 来获得一些辅助类型,如下所示:
template <typename ... T>
class TypeContainer: public std::tuple<T...>
{
public:
using BaseType = std::tuple<T...>;
static const size_t Size = sizeof...(T);
TypeContainer(T... args):std::tuple<T...>(args...){};
using index_sequence = std::index_sequence_for<T...>;
};
现在我尝试使用代码如下:
using MyType_tuple_with_empty = std::tuple< std::tuple<float,int>, std::tuple<>, std::tuple<int>>;
using MyType_typecontainer_with_empty = TypeContainer< TypeContainer<float,int>, TypeContainer<>, TypeContainer<int>>;
using MyType_tuple_non_empty = std::tuple< std::tuple<float,int>, std::tuple<int>, std::tuple<int>>;
using MyType_typecontainer_non_empty = TypeContainer< TypeContainer<float,int>, TypeContainer<int>, TypeContainer<int>>;
template <typename T>
void Do( const T& parms )
{
// The following lines result in errors if TypeContainer with
// empty element comes in. The empty element is in std::get<1> which
// is NOT accessed here!
std::cout << std::get<0>(std::get<0>(parms)) << " ";
std::cout << std::get<1>(std::get<0>(parms)) << std::endl;
std::cout << std::get<0>(std::get<2>(parms)) << std::endl;
}
int main()
{
MyType_tuple_with_empty p1{{ 1.2,3},{},{1}};
Do( p1 );
MyType_typecontainer_with_empty p2{{ 1.2,3},{},{1}};
Do( p2 ); // << this line raise the error
MyType_tuple_non_empty p3{{ 1.2,3},{4},{1}};
Do( p3 );
MyType_typecontainer_non_empty p4{{ 1.2,3},{4},{1}};
Do( p4 );
}
如果我用 Do(p2)
编译,我会得到以下错误:
error: no matching function for call to '
get(const TypeContainer<TypeContainer<float, int>, TypeContainer<>, TypeContainer<int> >&)
'
有人可以解释为什么与 std::get
相关的空 TypeContainer
的存在会导致该问题吗?
编辑: 附加信息:
线条
MyType_tuple_with_empty p1{{{ 1.2,3},{},{1}}};
MyType_tuple_non_empty p3{{ 1.2,3},{4},{1}};
gcc5.2.0 不能编译,gcc6.1.0 不能编译。这有点神秘,因为我记得元组的构造函数确实是显式的。为什么这适用于 gcc6.1.0?但这不是我搜索的问题:-)
另一个提示: 我遇到问题的代码似乎是用 clang3.5.0 编译的。
有点难懂...
编辑2: 挖掘错误列表(很长一个:-))我发现:
/opt/linux-gnu_5.2.0/include/c++/5.2.0/tuple|832 col 5| note: template argument deduction/substitution failed: main.cpp|104 col 45| note: '
std::tuple<_Elements ...>
' is an ambiguous base class of 'TypeContainer<TypeContainer<float, int>, TypeContainer<>, TypeContainer<int> >
' ||std::cout << std::get<0>(std::get<0>(parms)) << " "
;
似乎在 libg++ 中有人多次从任何似乎是损坏的库的元组类型派生。搜索此主题会将我带到:Empty nested tuples error
这真的有关系吗?相同错误或新错误:-)
很遗憾,您必须添加 get 函数的容器版本:
template <std::size_t I, typename ...T>
decltype(auto) get(TypeContainer<T...>&& v)
{
return std::get<I>(static_cast<std::tuple<T...>&&>(v));
}
template <std::size_t I, typename ...T>
decltype(auto) get(TypeContainer<T...>& v)
{
return std::get<I>(static_cast<std::tuple<T...>&>(v));
}
template <std::size_t I, typename ...T>
decltype(auto) get(TypeContainer<T...> const& v)
{
return std::get<I>(static_cast<std::tuple<T...> const&>(v));
}
并且在 Do
类函数中只使用 get
而不是 std::get
。编译器能够从参数中 select 命名空间。
我猜,我不确定,这是因为 gcc 有 EBO - Empty Base Optimization - implemented in its tuples. What are exact reason it is quite hard to guess. You might consider to report this in gcc bugzilla.
顺便说一句,从STD 类 衍生出来不是好习惯。如果您从组合而不是继承开始,那么您将需要提供自己的 get
函数并且您不会观察到此错误,可能会节省很多时间。