std::get using enum class as template argument

南笙酒味 提交于 2019-11-30 18:06:21

The strongly-typed enums introduced by C++11 cannot be implicitly converted into integral values of type say int, while std::get expects the template argument to be integral type.

You've to use static_cast to convert the enum values:

std::cout <<std::get<static_cast<int>(Bad::BAD)>(tup)<< std::endl; //Ok now!

Or you can choose to convert into underlying integral type as:

//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);
}

then use it as:

std::cout <<std::get<integral(Bad::BAD)>(tup)<< std::endl; //Ok now!

I'd like to add another answer because the original poster asked for a way to have a named access to elements of std::tuple through a class enum.

It is possible to have a template argument of the type of a class enum (at least in GCC). This makes it possible to define your own get retrieving the element of a tuple given a class enum value. Below is an implementation casting this value to int, but you could also do something more fancy:

#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 );
}

Note that std::get has two more variants (one for const tuple&, one for tuple&&), which can be implemented exactly the same way.

Yes, this was a bug in GCC 4.5. Scoped enums don't have implicit conversions to integral types.

A completely different solution would be:

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;

My solution is to use:

namespace Something{enum class Something {MY_INDEX_NAME = 0,OTHER_INDEX_NAME};};

2018 update:

It's not a problem anymore. I did have a problem when I tried variations of "enum class int", but this now works fine with VS 2017 15.7.2

enum 
{
  WIDTH,
  HEIGHT
};
std::get<HEIGHT>( Remaining ) = std::get<HEIGHT>( Remaining ) - MinHeight;
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!