函数模板特化强制枚举值带有类型
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;
}
输出:021
除非我完全错了…
sendMessage
和receiveMessage
可以有三个过载
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的评论
我的建议:
- 创建
struct
s作为标签而不是enum
。 - 使用标签
struct
s过载sendMessage
和receiveMessage
。
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
。
相关文章:
- 在有符号基础类型枚举的位域上溢出
- 在编译时将强类型枚举器转换为其基础类型?
- 如果 int 是"not within the enums range",为什么将 int 转换为强类型枚举会编译?
- 类型枚举的变量不是类型名称
- 强类型枚举的语法实现错误
- 枚举与强类型枚举
- 错误:T没有命名类型-用于使用强类型枚举的专门化
- 如何使用强类型枚举
- QT:将强类型枚举参数传递到插槽
- 在类定义中声明类型(枚举、结构等)会增加代码大小
- Visual Studio 11 (beta) 中的强类型枚举类
- 使用强类型枚举对类型和子类型进行建模
- 不允许将强类型枚举用作同一基础类型的参数
- 如何正确使用C++强类型枚举
- 带有强类型枚举的模板参数推导
- 是否可以在googleprotobuf中为类型(枚举或消息)定义一个别名
- C++中默认初始化的全局强类型枚举是什么
- std::is_signed不适用于强类型枚举:int
- 如何定义自定义值的类型?(枚举类型定义)
- 将强类型枚举传递给函数