【问题标题】:Using SFINAE to detect a member function [duplicate]使用 SFINAE 检测成员函数 [重复]
【发布时间】:2013-09-05 09:21:01
【问题描述】:

在C++11中,要判断一个类是否有成员函数size,可以定义如下的测试助手:

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);
};

在 C++98 中是否有类似的技巧可以在不依赖编译器扩展(例如 typeof)的情况下执行此操作?

【问题讨论】:

  • 这也会检测数据成员。
  • 这可能有用:en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Member_Detector -- 编辑: 还有:stackoverflow.com/questions/257288/…(不要停留在第一个答案上)
  • @jrok 没关系,它将在模板函数中使用,如果它不是函数,则会导致编译错误 - 我可以忍受。
  • @nijansen 如果size 是私有的而不是SFINAE,它也会触发一个硬错误。在 C++98 中你也必须忍受它,除非你从 gx_ 的评论中切换到该技术。

标签: c++ sfinae c++98


【解决方案1】:

实际上,您的检测可能是错误的。

问题是您所检测到的只是C 有一个成员size

  • 它可能是一个属性
  • 可以是任何签名的方法
  • 甚至可以有多种方法(具有各种签名)

如果您希望加强检测,您应该尝试仅检测 权利 size(无论权利是什么)。 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);
};

编辑: with overloads.

处理不正确的size 成员的技巧是really_has 结构。不过,我并没有假装它是完美的……

在 C++11 中,things are simpler(虽然同样冗长)因为您可以通过 use 直接检测事物。因此,等效特征是:

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);
};

但是,C++ 中推荐的方法是尽可能不要使用特征;例如在函数中,您可以在类型签名中使用decltype

【讨论】:

  • 不幸的是,我在这里绑定了 C++98;我可以同时允许size_t size()size_t size() const 作为签名吗?
  • @nijansen:可以,但这有意义吗?请注意,如果您的函数是void doSomething(C const&amp; container),则需要使用const 方法:)。请参阅编辑后的答案以了解如何操作。
  • 是的,我不得不将其更改为按值传递它,因为我必须使用一些不太喜欢 const 正确性的库......我仍然希望我的 has_size 元函数与这些库容器和 STL 容器兼容
  • @nijansen:哎呀,传值确实如此。你意识到它意味着容器的副本吗?您最好先提供代理template &lt;typename T&gt; class Proxy { Proxy(T&amp; t): _t(t) {} size_t size() const { return _t.size(); } ... };,然后再提供Proxy proxy(container); doSomething(proxy);
  • 你是对的 - 这是一个绝妙的主意。谢谢
猜你喜欢
  • 2011-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多