如何实现枚举值到类模板的隐式转换

How to achieve implicit conversion from enum value to class template

本文关键字:转换 何实现 实现 枚举      更新时间:2023-10-16

假设我有一些枚举enum EnumA { fooA, barA, quuzA };, enum EnumB {fooB, barB, quuzB };等和一些模板结构体的形式:

template<EnumA value> struct StructA {};
template<EnumB value> struct StructB {};

等等。我想实现从枚举值到相应结构体的隐式转换,显然当枚举值是编译时常数时。

对于更多上下文,我希望能够在以下上下文中使用它。我有一个函数

template<typename T> void somefunc(int somepar, T);

,我可以用它作为somefunc(somepar, StructB<quuzB>());,我想用它作为somefunc(somepar, quuzB);

(不,重载somefunc作为一组模板函数,每个枚举一个,这做适当的结构包装本身不是一个选项,由于(1)枚举的数量和(2)的事实,我也想有一些像template<typename T1, typename T2> void somefunc(int par1, T1, int par2, T2)使用somefunc(p1, StructB<quuzB>(), p2, StructA<barA>())等)

您希望在调用中作为实际参数提供的enum值最终作为运行时值。但是要将其转换为特定于值的类型,需要在编译时了解该值。目前,您正在手动提供编译时知识,并且使用您建议的更简单的调用语法,获取该知识的唯一通用方法是通过一些源代码预处理。

为了避免预处理(通过任何方式,例如宏或脚本,或训练的黑猩猩),您可以调整调用语法的要求,例如显式地提供enum类型,因此,而不是

somefunc( somepar, quuzB );

白马王子;你会写

somefunc<EnumB, quuzB>( somepar );

示例,其中宏的东西只是为了说明,以防您想要,但我建议不使用宏(显式是好的,隐式是坏的):

enum EnumA { fooA, barA, quuzA };
enum EnumB { fooB, barB, quuzB };
template< EnumA value> struct StructA {};
template< EnumB value> struct StructB {};
//template<typename T> void somefunc( int somepar, T );
template< class Enum_type, Enum_type value >
void somefunc( int somepar );
void foo()
{
    somefunc<EnumB, quuzB>( 42 );
}
//-------------------------------------------------------------
#define SOMEFUNC( par, e ) somefunc<decltype(e), e>( par )
void bar()
{
    SOMEFUNC( 42, quuzB );
}
//-------------------------------------------------------------
#include <iostream>
#include <string>
#include <typeinfo>
using namespace std;
#ifdef __GNUC__
#   include <cxxabi.h>
    auto demangled( char const name[] )
        -> string
    {
        int status = 0;
        char* c_result = abi::__cxa_demangle( name, 0, 0, &status);
        string result = c_result;
        free( c_result );
        return result;
    }
#else
    auto demangled( char const name[] )
        -> string
    { return name; }
#endif
template< class Type >
void somefunc_impl( int x, Type )
{
    cout << x << ", " << demangled( typeid( Type ).name() ) << endl;
}
template< class Enum_type >
struct Enum_to_struct;
template<>
struct Enum_to_struct<EnumA>
{
    template< EnumA e > struct Struct{ using T = StructA<e>; };
};
template<>
struct Enum_to_struct<EnumB>
{
    template< EnumB e > struct Struct{ using T = StructB<e>; };
};
template< class Enum_type, Enum_type value >
void somefunc( int somepar )
{
    using Struct = typename Enum_to_struct<Enum_type>::template Struct<value>::T;
    somefunc_impl( somepar, Struct() );
}
auto main() -> int
{
    foo();
    bar();
}

可以简化为& & &;你可以避免Enum_to_struct特征–通过使用部分专门化的类模板,而不是不相关的单独命名的模板,如StructAStructB

enum EnumA { fooA, barA, quuzA };
enum EnumB { fooB, barB, quuzB };
template< class Enum_type, Enum_type value >
struct Struct{};
template< EnumA e >
struct Struct< EnumA, e > {}; // Whatever, corresponding to StructA
template< class Enum_type, Enum_type value >
void somefunc( int somepar );
void foo()
{
    somefunc<EnumB, quuzB>( 42 );
}
//-------------------------------------------------------------
#define SOMEFUNC( par, e ) somefunc<decltype(e), e>( par )
void bar()
{
    SOMEFUNC( 42, quuzB );
}
//-------------------------------------------------------------
#include <iostream>
#include <string>
#include <typeinfo>
using namespace std;
#ifdef __GNUC__
#   include <cxxabi.h>
    auto demangled( char const name[] )
        -> string
    {
        int status = 0;
        char* c_result = abi::__cxa_demangle( name, 0, 0, &status);
        string result = c_result;
        free( c_result );
        return result;
    }
#else
    auto demangled( char const name[] )
        -> string
    { return name; }
#endif
template< class Type >
void somefunc_impl( int x, Type )
{
    cout << x << ", " << demangled( typeid( Type ).name() ) << endl;
}
template< class Enum_type, Enum_type value >
void somefunc( int somepar )
{
    somefunc_impl( somepar, Struct<Enum_type, value>() );
}
auto main() -> int
{
    foo();
    bar();
}

为了完整起见,即使宏是邪恶的™我不建议使用它们,如果你选择宏路径,你可以将开销减少到单个宏而不是每个函数一个宏,代价是调用语法不太明显:

#define TV( v ) decltype( v ), v
void qwepoi()
{
    somefunc<TV( quuzB )>( 42 );
}