繁体   English   中英

函数模板特化以强制枚举值与类型

[英]Function template specialization to force enum value with type

在给定消息类型和特定于消息类型的类型的数据结构的情况下,需要一个函数来发送消息:

enum class MsgType
{
    msgInt,
    msgDouble,
    msgString
};

template < some template here >
void sendMessage(MsgType type, T value);

我希望以下列方式调用此函数:

sendMessage( MsgType::msgInt, 42 );
sendMessage( MsgType::msgString, "Answer to the life, etc,etc.");
//sendMessage( MsgType::msgDouble, "Should not compile");
//sendMessage<MsgType::msgString>( "That is easy!" );

我怎样才能实现前面描述的模板功能专业化?

注意:如果可能,使用C ++ 11,但C ++ 14也是可以接受的。

编辑:

当前实现,它只接受MsgType作为模板参数(而不是函数参数)。

template<MsgType Id, typename T>
void sendMessage(T data);

template<>void sendMesssage<MsgType::msgNumCar, int>( int data ){ //...   }
template<>void sendMesssage<MsgType::msgInt, int>( int data ){ //...   }
template<>void sendMesssage<MsgType::msgString, string>( string data ){ //...   }
// A call
sendMessage<MsgType::msgNumCar>( 42 );

模板可以具有编译时已知的常量参数。 您可以执行以下操作:

enum MsgType {
    msgInt,
    msgDouble,
    msgString
};

template<int>
struct Message { };

template<>
struct Message<MsgType::msgInt> {
    static void send(int value) { cout << "int: " << value; }
};

template<>
struct Message<MsgType::msgDouble> {
    static void send(double value) { cout << "double: " << value; }
};

template<>
struct Message<MsgType::msgString> {
    static void send(const char* value) { cout << "string: " << value; }
};

并调用它:

Message<MsgType::msgInt>::send(5);
Message<MsgType::msgDouble>::send(3.14);
Message<MsgType::msgString>::send("hello");

// will not compile
//Message<MsgType::msgDouble>::send("should not compile");

请注意,模板参数必须是常量(即在编译时已知)。 这意味着以下代码将无法编译:

int type = MsgType::msgInt;
Message<type>::send(123);

但是,为什么不为sendMessage创建3个重载?

而不是验证用户将正确的消息类型枚举值传递到send函数,而是完全使用某些特征来防止它:

#include <iostream>

enum class MsgType
{
    msgInt,
    msgDouble,
    msgString
};

template <typename T>
struct MsgTypeOf;

template <>
struct MsgTypeOf<int>
{
    static MsgType msg_type;
};

template <>
struct MsgTypeOf<double>
{
    static MsgType msg_type;
};

template <>
struct MsgTypeOf<const char*>
{
    static MsgType msg_type;
};

MsgType MsgTypeOf<int>::msg_type = MsgType::msgInt;
MsgType MsgTypeOf<double>::msg_type = MsgType::msgDouble;
MsgType MsgTypeOf<const char*>::msg_type = MsgType::msgString;

template <typename T>
int sendMessage(T value)
{
    return static_cast<int>(MsgTypeOf<T>::msg_type);
}

int main()
{
    std::cout << sendMessage(42) << std::endl;
    std::cout << sendMessage("Answer to the life, etc,etc.") << std::endl;
    std::cout << sendMessage(42.42) << std::endl;
}

输出:0 2 1

除非我完全偏离基地......

您可以有三个sendMessagereceiveMessage重载。

void sendMessage(int m);
void sendMessage(double m);
void sendMessage(std::string const& m);

void receiveMessage(int& m);
void receiveMessage(double& m);
void receiveMessage(std::string& m);

不需要enum或功能模板。

更新,以回应OP的评论

我的建议:

  1. 创建struct s到被用作标签,而不是一个enum
  2. 使用标记struct s重载sendMessagereceiveMessage

struct int_message_t {};
struct double_message_t {};
struct string_message_t {};
struct username_message_t {};
struct numcars_message_t {};
struct bigstruct_message_t {};

然后使用它们重载它们

void sendMessage(int_message_t, int m);
void sendMessage(double_message_t, double m);
void sendMessage(string_message_t, std::string const& m);
void sendMessage(username_message_t, std::string const& m);
void sendMessage(numcars_message_t, int m);
void sendMessage(bigstruct_message_t, big_struct const& m);

void receiveMessage(int_message_t, int& m);
void receiveMessage(double_message_t, double& m);
void receiveMessage(string_message_t, std::string& m);
void receiveMessage(username_message_t, std::string& m);
void receiveMessage(numcars_message_t, int& m);
void receiveMessage(bigstruct_message_t, big_struct& m);

如果您可以使用函数模板来实现这些函数的实现,那将会很好,但我仍然会将其作为实现细节。

保留您提供的确切方法调用不能在错误的枚举类型上给出编译错误,因为发送的枚举类型仅在运行时已知(作为方法参数)。 并且您不能在函数参数值上重载(仅在类型上)。

将枚举作为模板参数( @IdanYadgar )可以在编译时进行检查。

类型重载( @MarkB@RSahu - 使用两种不同的方法)也是一个不错的选择。

我相信@RSahu是你能得到的最接近你所要求的。 也许你可以为每个struct添加一个static const int value ,因此它实际上将用作enum

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM