13

我使用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 中修复的?我可以使用一个简单的枚举,但我喜欢枚举类的作用域属性,所以如果可能的话,我更喜欢使用后者。

4

6 回答 6

10

C++11 引入的强类型枚举不能隐式转换为 say 类型的整数值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!
于 2012-05-24T17:20:46.873 回答
6

我想添加另一个答案,因为原始海报要求一种通过类枚举对 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还有两个变体(一个 for const tuple&,一个 for tuple&&),可以完全相同的方式实现。

于 2013-02-12T15:10:00.330 回答
3

是的,这是 GCC 4.5 中的一个错误。作用域枚举没有到整数类型的隐式转换。

于 2012-05-24T17:19:24.793 回答
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;
于 2012-05-24T22:41:56.727 回答
0

2018年更新:

这不再是问题了。当我尝试“枚举类 int”的变体时,我确实遇到了问题,但这现在适用于 VS 2017 15.7.2

enum 
{
  WIDTH,
  HEIGHT
};
std::get<HEIGHT>( Remaining ) = std::get<HEIGHT>( Remaining ) - MinHeight;
于 2018-05-31T16:28:30.883 回答
-1

我的解决方案是使用:

namespace Something{enum class Something {MY_INDEX_NAME = 0,OTHER_INDEX_NAME};};
于 2016-10-02T09:45:12.677 回答