【问题标题】:How to find if a method of a particular prototype exists inside a class?如何查找特定原型的方法是否存在于类中?
【发布时间】:2012-11-20 07:52:10
【问题描述】:

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

我必须检查某个给定对象是否提供了一些函数来执行自定义序列化并调用此函数,或者在未提供自定义序列化方法时执行简单的memcpysizeof(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&lt;class Type, class Return, class Parameter, Return (Type::* Pointer)(Parameter)const&gt;

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

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

以下是问题:

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

【问题讨论】:

  • 是否允许const void * const?您是在告诉编译器您有一个 const void 类型的对象。但是无论如何都不能修改空隙AFAIK?如果您尝试void * const,会发生什么?
  • 好问题。似乎 GCC 不接受 template &lt; typename Type, typename Return, typename Parameter, Return (Type::*)( void ) &gt; struct sMemberMethod { }; 作为参数。然而,MSVC 对此持开放态度。
  • 我相信 iammilind 是对的。与 C 不同,C++ 不允许在函数的参数列表中使用 void。这是因为在 C 中,f() 是一个没有原型的函数(= 未指定参数),而在 C++ 中,f() 是一个没有参数的函数。

标签: c++ templates visual-c++ gcc sfinae


【解决方案1】:

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

为什么代码在 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&lt;ClassName, ClassMethodType&gt;::value 给你答案是否存在某种类型的成员方法。
截至目前,HasMethod&lt;&gt;方法命名 size 所独有的,具有用户提供的类型。但是您可以为上面的代码创建一个宏,并使函数名可配置

这是working demo with g++

【讨论】:

  • 很好的答案!不幸的是,示例代码并不完全适合我的需要,但指导我很好地解决了主要问题,顺便说一句:感谢纠正我糟糕的英语;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-22
  • 1970-01-01
  • 1970-01-01
  • 2017-07-06
  • 2021-10-05
  • 1970-01-01
  • 2016-12-23
相关资源
最近更新 更多