我正在使用std::tuple
并定义了一个类枚举,以某种方式“命名”每个元组的字段,忘记了它们的实际索引。
所以不要这样做:
std::tuple<A,B> tup;
/* ... */
std::get<0>(tup) = bleh; // was it 0, or 1?
我这样做了:
enum class Something {
MY_INDEX_NAME = 0,
OTHER_INDEX_NAME
};
std::tuple<A,B> tup;
/* ... */
std::get<Something::MY_INDEX_NAME> = 0; // I don't mind the actual index...
问题是,由于这是使用gcc 4.5.2编译的,我现在已经安装了4.6.1版本,我的项目无法编译。此代码段会重现错误:
#include <tuple>
#include <iostream>
enum class Bad {
BAD = 0
};
enum Good {
GOOD = 0
};
int main() {
std::tuple<int, int> tup(1, 10);
std::cout << std::get<0>(tup) << std::endl;
std::cout << std::get<GOOD>(tup) << std::endl; // It's OK
std::cout << std::get<Bad::BAD>(tup) << std::endl; // NOT!
}
该错误基本上表示没有超载符合我对std::get
的调用:
test.cpp: In function ‘int main()’:
test.cpp:16:40: error: no matching function for call to ‘get(std::tuple<int, int>&)’
test.cpp:16:40: note: candidates are:
/usr/include/c++/4.6/utility:133:5: note: template<unsigned int _Int, class _Tp1, class _Tp2> typename std::tuple_element<_Int, std::pair<_Tp1, _Tp2> >::type& std::get(std::pair<_Tp1, _Tp2>&)
/usr/include/c++/4.6/utility:138:5: note: template<unsigned int _Int, class _Tp1, class _Tp2> const typename std::tuple_element<_Int, std::pair<_Tp1, _Tp2> >::type& std::get(const std::pair<_Tp1, _Tp2>&)
/usr/include/c++/4.6/tuple:531:5: note: template<unsigned int __i, class ... _Elements> typename std::__add_ref<typename std::tuple_element<__i, std::tuple<_Elements ...> >::type>::type std::get(std::tuple<_Elements ...>&)
/usr/include/c++/4.6/tuple:538:5: note: template<unsigned int __i, class ... _Elements> typename std::__add_c_ref<typename std::tuple_element<__i, std::tuple<_Elements ...> >::type>::type std::get(const std::tuple<_Elements ...>&)
那么,有没有什么方法可以将我的枚举类用作std::get
的模板参数?这是不是编译的东西,并在gcc 4.6中修复?我可以使用一个简单的枚举,但我喜欢枚举类的作用域属性,所以如果可能的话,我更愿意使用后者。
答案 0 :(得分:10)
C ++ 11引入的强类型枚举不能隐式转换为类型为int
的整数值,而std::get
期望模板参数为整数类型。
您必须使用static_cast
转换枚举值:
std::cout <<std::get<static_cast<int>(Bad::BAD)>(tup)<< std::endl; //Ok now!
或者您可以选择转换为基础整数类型:
//note that it is constexpr function
template <typename T>
constexpr typename std::underlying_type<T>::type integral(T value)
{
return static_cast<typename std::underlying_type<T>::type>(value);
}
然后将其用作:
std::cout <<std::get<integral(Bad::BAD)>(tup)<< std::endl; //Ok now!
答案 1 :(得分:4)
我想添加另一个答案,因为原始海报要求通过类枚举对std :: tuple元素进行命名访问。
可以使用类枚举类型的模板参数(至少在GCC中)。这使得可以定义自己的get
,在给定类枚举值的情况下检索元组的元素。下面是将此值转换为int的实现,但您也可以做一些更奇特的事情:
#include <tuple>
enum class names { A = 0, B, C };
template< names n, class... Types >
typename std::tuple_element<static_cast< std::size_t >( n ), std::tuple<Types...> >::type&
get( std::tuple<Types...>& t )
{
return std::get< static_cast< std::size_t >( n ), Types... >( t );
}
int main( int, char** )
{
std::tuple< char, char, char > t( 'a', 'b', 'c' );
char c = get<names::A>( t );
}
请注意,std::get
还有两个变体(一个用于const tuple&
,一个用于tuple&&
),可以完全相同的方式实现。
答案 2 :(得分:3)
是的,这是GCC 4.5中的一个错误。 Scoped枚举没有对整数类型的隐式转换。
答案 3 :(得分:2)
完全不同的解决方案是:
A& my_field(std::tuple<A,B>& t) { return std::get<0>(t); }
A const& my_field(std::tuple<A,B> const& t) { return std::get<0>(t); }
B& my_other_field(std::tuple<A,B>& t) { return std::get<1>(t); }
B const& my_other_field(std::tuple<A,B> const& t) { return std::get<1>(t); }
my_field(t) = blah;
my_other_field(t) = frob;
答案 4 :(得分:0)
我的解决方案是使用:
namespace Something{enum class Something {MY_INDEX_NAME = 0,OTHER_INDEX_NAME};};
答案 5 :(得分:0)
2018更新:
这不再是问题了。当我尝试使用“enum class int”的变体时,我确实遇到了问题,但现在可以使用VS 2017 15.7.2了。
enum
{
WIDTH,
HEIGHT
};
std::get<HEIGHT>( Remaining ) = std::get<HEIGHT>( Remaining ) - MinHeight;