[英]Forcing type conversion in C++ using SFINAE
我正在编写一个类(BufferInserter),该类将用户定义的消息透明地转换为他们的网络字节序格式,并将结果打包到用户提供的缓冲区中。 这是一条消息及其字节交换对象的简单示例:
//Native message (not in network endian format)
struct Message
{
short val;
Message(short v): val(v){}
};
//Network endian format of Message
struct OtaMessage
{
typedef Message NativeType;
short val;
operator Message() const
{
return Message(val >> 8 | val << 8);
}
OtaMessage(const Message& m)
: val(val >> 8 | val << 8)
{}
};
这是BufferInserter的高度简化版本:
class BufferInserter
{
public:
BufferInserter(char* buffer)
:buf(buffer)
{}
template<typename T>
char* insertStruct(T s, typename T::NativeType = 0)
{
const std::size_t size = sizeof(T);
*reinterpret_cast<T*>(buf) = s;
buf += size;
return buf;
}
private:
char* buf;
};
希望用户可以执行以下操作:
Message m(1);
char buf[256];
BufferInserter ins(buf);
ins.insertStruct(m);
C ++类型推导机制会跳过将本机Message传递给insertStruct的原因,因为Message没有NativeType typedef,而是将Message转换为OtaMessage。 那不是发生了什么,而是出现编译器错误(g ++ 4.7)
test.cpp:55:23: error: no matching function for call to ‘BufferInserter::insertStruct(Message&)’
ins.insertStruct(m);
^
test.cpp:55:23: note: candidate is:
test.cpp:34:11: note: template<class T> char* BufferInserter::insertStruct(T, typename T::NativeType)
char* insertStruct(T s, typename T::NativeType = 0)
^
test.cpp:34:11: note: template argument deduction/substitution failed:
test.cpp: In substitution of ‘template<class T> char* BufferInserter::insertStruct(T, typename T::NativeType) [with T = Message]’:
test.cpp:55:23: required from here
test.cpp:34:11: error: no type named ‘NativeType’ in ‘struct Message’
MSVC 2013存在类似错误,因此它可能不是编译器错误。
显然,这可行:
Message m(1);
char buf[256];
BufferInserter ins(buf);
ins.insertStruct(OtaMessage(m));
但是我想避免用户必须了解字节交换。 我还可以在Message结构中向OtaMessage添加一个转换运算符:
struct Message
{
short val;
Message(short v): val(v){}
operator OtaMessage()
{
val = v<<8 | v>>8;
}
};
有两个问题:
1> Source.cpp(74):致命错误C1001:编译器发生内部错误。 1>(编译器文件'msc1.cpp',第1325行)1>要变通解决此问题,请尝试简化或更改上述位置附近的程序。
有什么帮助吗?
那不是类型推导的原理。 也许您可以实现类似特征的方法,让BufferInserter::insertStruct<Message>
推导,然后与特征类一起转换。 它的一些关键部分可能看起来像这样:
template <typename T>
struct OtaConverter {
// using ota_type = T; -- don't provide a base ota_type
};
: : :
template <> struct OtaConverter<Message> {
using ota_type = OtaMessage;
};
: : :
template<typename T>
char* BufferInserter::insertStruct(T s, typename OtaConverter<T>::ota_type* = 0)
{
using OT = typename OtaConverter<T>::ota_type;
const std::size_t size = sizeof(OT);
*reinterpret_cast<OT*>(buf) = OT(s);
buf += size;
return buf;
}
您还需要修复OtaMessage
构造函数,因为它目前未引用m.val
。 为了安全起见,还应该将构造函数标记为显式。
请参见此示例 。 请注意,删除OtaConverter
的专业化当前会导致故意的编译错误。
我遇到了相同的问题(在其他情况下),并且通过更新MSVC2013工具->扩展和更新->更新->产品更新(自更新2开始已修复错误https://support.microsoft.com/fr-fr / kb / 2927432 )。
干杯,
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.