C++ 在C+中强制类型转换+;使用SFINAE

C++ 在C+中强制类型转换+;使用SFINAE,c++,sfinae,C++,Sfinae,我正在编写一个类(BufferInserter),它透明地将用户定义的消息转换为其网络端格式,并将结果打包到用户提供的缓冲区中。下面是消息及其字节交换对应项的简单示例: //Native message (not in network endian format) struct Message { short val; Message(short v): val(v){} }; //Network endian format of Message struct OtaMessa

我正在编写一个类(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)
    {}
};

和C++类型的演绎机制会跳过原生消息传递到插入结构,因为消息没有NativeType typedef,相反,它会将消息转换为OTAMESGE。事实并非如此,相反,我得到了编译器错误(g++4.7)

但是我想避免用户必须知道字节交换。我还可以向消息结构中的消息添加转换运算符:

struct Message
{
    short val;
    Message(short v): val(v){}
    operator OtaMessage()
    {
       val = v<<8 | v>>8;
    }
};
struct消息
{
短val;
信息(短v):val(v){}
运算符消息()
{
val=v8;
}
};
这有两个问题:

  • 同样,我不希望用户知道这条消息
  • OtaMessage是在消息之后定义的,因此消息-->OtaMessage是不可能的。有趣的是,在MSVC 2013中尝试此操作后,我使编译器崩溃:
  • 1> Source.cpp(74):致命错误C1001:编译器中发生内部错误。 1> (编译器文件“msc1.cpp”,第1325行) 1> 要解决此问题,请尝试在上面列出的位置附近简化或更改程序


    有什么帮助吗?

    这不是类型推断的工作方式。也许您可以实现一种类似traits的方法,让
    BufferInserter::insertStruct
    被推导出来,然后用traits类进行转换。它的一些关键部分可能如下所示:

    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;
    }
    
    模板
    结构转换器{
    //使用ota_type=T;--不提供基本的ota_类型
    };
    : : :
    模板结构转换器{
    使用ota_type=ota消息;
    };
    : : :
    模板
    char*BufferInserter::insertStruct(TS,类型名OtaConverter::ota_type*=0)
    {
    使用OT=typename-otacverter::ota\u-type;
    常数std::size\u t size=sizeof(OT);
    *重新解释铸造(buf)=OT(s);
    buf+=尺寸;
    返回buf;
    }
    
    您还需要修复您的
    OtaMessage
    构造函数,因为它当前未引用
    m.val
    。为安全起见,您还应明确标记构造函数


    看这个。请注意,删除OtaConverter的专用化当前会导致故意编译错误。

    我遇到了相同的问题(在其他情况下),我通过更新MSVC2013工具->扩展和更新->更新->产品更新(自更新2以来已修复错误)来修复它


    干杯,

    此错误消息相关:
    test.cpp:34:11:错误:在“struct message”中没有名为“NativeType”的类型。
    。您在
    OtaMessage
    中有一个
    NativeType
    ,但编译器正在
    Message
    中查找它。是的,我知道。我希望C++类型的演绎机制在尝试使用消息作为ARG来插入结构时,会看到和失败,然后找到OTAMESEGE(因为它确实有本土化)。不,它不是那么聪明。在推导模板函数参数的类型时,它不会首先尝试使用
    operator()
    等转换它们。您可以创建一个类型特征和一个帮助器类模板来完成转换。
    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’
    
    Message m(1);
    char buf[256];
    BufferInserter ins(buf);
    ins.insertStruct(OtaMessage(m));
    
    struct Message
    {
        short val;
        Message(short v): val(v){}
        operator OtaMessage()
        {
           val = v<<8 | v>>8;
        }
    };
    
    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;
    }