Using SFINAE to detect a member function [duplicat

2019-04-06 06:49发布

This question already has an answer here:

In C++11, to find out whether a class has a member function size, you could define the following test helper:

template <typename T>
struct has_size_fn
{
    typedef char (& yes)[1];
    typedef char (& no)[2];

    template <typename C> static yes check(decltype(&C::size));
    template <typename> static no check(...);

    static bool const value = sizeof(check<T>(0)) == sizeof(yes);
};

Is there a similar trick for doing this in C++98 without relying on compiler extensions such as typeof?

标签: c++ sfinae c++98
2条回答
淡お忘
2楼-- · 2019-04-06 07:13

Yes:

char (*)[sizeof(&C::size)]
查看更多
ら.Afraid
3楼-- · 2019-04-06 07:27

Actually, your detection is potentially erroneous.

The problem is that all you are detecting is that C has a member size:

  • it could be an attribute
  • it could be a method with whatever signature
  • there could even be several methods (with various signatures)

If you wish to harden the detection, you should attempt to detect only the right size (for whatever right is). Here is such a hardened detection.

template <typename T>
class has_size {
private:
  typedef char Yes;
  typedef Yes No[2];

  template <typename U, U> struct really_has;

  template <typename C> static Yes& Test(really_has <size_t (C::*)() const,
                                        &C::size>*);

  // EDIT: and you can detect one of several overloads... by overloading :)
  template <typename C> static Yes& Test(really_has <size_t (C::*)(),
                                        &C::size>*);

  template <typename> static No& Test(...);

public:
    static bool const value = sizeof(Test<T>(0)) == sizeof(Yes);
};

Edit: with overloads.

The trick to deal with incorrect size members is the really_has structure. I make no pretense that it is perfect, though...

In C++11, things are simpler (though no less verbose) because you can detect things by use directly. The equivalent trait is thus:

template <typename T>
class has_size {
private:
  typedef char Yes;
  typedef Yes No[2];

  template<typename C> static auto Test(void*)
    -> decltype(size_t{std::declval<C const>().size()}, Yes{});

  template<typename> static No& Test(...);

public:
    static bool const value = sizeof(Test<T>(0)) == sizeof(Yes);
};

However, the recommended method in C++ is not to use traits if you can; in functions for example you can use decltype right in the type signature.

查看更多
登录 后发表回答