5

我正在使用一些 SFINAE 功能;当前位于必须在 Linux 和 Windows 中运行的应用程序的一部分中;编译器选择是用于 Windows 应用程序的 MSVC (Visual Studio 2010 10.0) 和用于 Linux 应用程序的 GCC 4.4.5。

我必须检查某个给定对象是否提供了一些函数来执行自定义序列化并调用此函数,或者在未提供自定义序列化方法的情况下执行简单的memcpy操作。sizeof(Object)

问题是一段代码在 MSVC 中编译时没有警告或错误,但在使用 GCC 编译时,代码如下:

template
    <
        typename Type,
        typename Return,
        typename Parameter,
        Return (Type::*Pointer)(Parameter) const
    > struct sMemberMethodConst { };

template
    <
        typename Type,
        typename Return,
        typename Parameter,
        Return (Type::*)(Parameter)
    > struct sMemberMethod { };

template<typename T> struct sMemberMethodChecker
{
    template <typename Type> static char HasCustomSizeMethod(sMemberMethodConst<Type, size_t, void, &Type::Size> *);
    template <typename Type> static long HasCustomSizeMethod(...);
    template <typename Type> static char HasSerializeMethod(sMemberMethodConst<Type, size_t, void * const, &Type::Serialize> *);
    template <typename Type> static long HasSerializeMethod(...);
    template <typename Type> static char HasDeserializeMethod(sMemberMethod<Type, size_t, const void * const, &Type::Deserialize> *);
    template <typename Type> static long HasDeserializeMethod(...);
    // Other specific method checks...

    enum
    {
        HAS_CUSTOM_SIZE_METHOD =    (sizeof(HasCustomSizeMethod<T>(0)) == sizeof(char)),
        HAS_SERIALIZE_METHOD =      (sizeof(HasSerializeMethod<T>(0)) == sizeof(char)),
        HAS_DESERIALIZE_METHOD =    (sizeof(HasDeserializeMethod<T>(0)) == sizeof(char)),
        IS_CUSTOM =                 HAS_CUSTOM_SIZE_METHOD &&
                                    HAS_SERIALIZE_METHOD &&
                                    HAS_DESERIALIZE_METHOD,
        // Other 'shortcuts'...
    };

我在使用 GCC 编译时遇到的错误是:

invalid parameter type 'void' in declaration template<class Type, class Return, class Parameter, Return (Type::* Pointer)(Parameter)const>

在的第一行struct sMemberMethodChecker。我很确定我没有遗漏typenames 或放错词,但我不明白为什么我会收到错误并且不理解错误。

我知道 MSVC 的标准松懈,而 GCC 非常符合标准,所以我想知道问题是否出在允许愚蠢代码的 MSVC 方面!

以下是问题:

  • 为什么我在?中收到invalid parameter type 'void'错误消息。struct sMemberMethodChecker
  • 为什么代码在 MSVC 中有效但在 GCC 中无效?
  • 这个代码是非标准的吗?
  • SFINAE 诡计是 C++11 独有的吗?
4

1 回答 1

2

为什么我在结构 sMemberMethodChecker 中收到无效参数类型“void”错误?。

为什么代码在 MSVC 中有效但在 GCC 中无效?

我相信 MSVC 很有帮助,但是 GCC 在这个特定的代码中很严格。因为它以某种方式不允许Return (Type::*)(void)。但是,需要更多地挖掘它才能知道确切的原因。

这个代码不标准吗?

不能说,直到它不编译。SFINAE 等功能的搜索标准并不是每个人都喜欢。

SFINAE 诡计是 C++11 独有的吗?

一点也不。SFINAE 在 C++11 之前就已经存在。
这是您想要做的简化方法:

template<typename ClassName, typename ClassMethodType>
struct HasMethod
{
  template<typename Type, Type Object> struct Contains;
  typedef char (&yes)[2];

  template<typename Class, typename MethodType>
  static yes Check (Contains<MethodType, &Class::size>*);
  template<typename Class, typename MethodType>
  static char Check (...);

  static const bool value = (sizeof(Check<ClassName,ClassMethodType>(0)) == sizeof(char));
};

HasMethod<ClassName, ClassMethodType>::value如果其中是否存在某种类型的成员方法,则会为您提供答案。
到目前为止,HasMethod<>仅使用用户提供的类型命名方法。 size但是您可以为上述代码创建一个宏并使函数名称可配置

这是一个使用 g++ 的工作演示

于 2012-11-20T08:45:13.070 回答