其他分享
首页 > 其他分享> > c – SFINAE会员通过

c – SFINAE会员通过

作者:互联网

我想知道是否有可能创建一个类作为std :: enable_if和SFINAE成员检测器之间的组合.

class foo
{
public:
    int bar;
};

template <class T>
typename enable_if_has_bar<T>::type ReturnBar (const T& value)
{
    return value.bar;
}

所以我试图这样做.

class foo
{
public:
    int bar;
};

template <class C, C>
class Check;

template <class T, class Enable = void>
class enable_if_has_bar
{};

template <class T>
class enable_if_has_bar<T, Check <decltype(&T::bar),&T::bar>>
{
public:
    typedef decltype(static_cast<T*>(0)->*static_cast<decltype(&T::bar)>(0)) type;
};

template <class T>
typename enable_if_has_bar<T>::type ReturnBar (const T& value)
{
    return value.bar;
}

int main ()
{
    foo foobar;
    foobar.bar = 42;

    cout << ReturnBar(foobar) << endl;
}

(http://ideone.com/WKTfmQ)

它似乎不起作用,而且我对SFINAE的艺术不太熟悉.也许有人可以改进/修复它?因为我不知所措.

解决方法:

我通常更喜欢按照您的尝试创建自定义的enable_if样式类型,因为我发现使用单个特征类型读取的代码更清晰,而不是enable_if< some_trait< T>,another_trait< T>>的组合.但在这种情况下,您的代码中有一些问题会阻止它正常工作.

您的enable_if_has_bar特化永远不会被选中,ReturnBar的返回类型只是实例化主模板,enable_if_has_bar< foo,void>,并且永远不会定义嵌套类型.什么都没有导致专业化被实例化,所以没有什么可以检查T :: bar是否是一个有效的表达式.

您的decltype(static_cast< T *>(0) – > * static_cast< decltype(& T :: bar)>(0))表达式将导致int&你可能想要的不是int.这是因为decltype(foobar.*(& foo :: bar))等同于decltype(foobar.bar)而foobar.bar是左值,因此decltype是int&amp ;.如果返回int&函数ReturnBar将无法编译因为参数值是const,所以你不能将value.bar绑定到非const int&amp ;.

这是一个工作版本:

template <class T>
  class has_bar
  {
    template<typename U, typename = decltype(&U::bar)>
      static std::true_type
      test(U*);

    static std::false_type
    test(...);

  public:
    static const int value = decltype(test((T*)nullptr))::value;
  };

template<typename T, bool = has_bar<T>::value>
  struct enable_if_has_bar
  { };

template<typename T>
  struct enable_if_has_bar<T, true>
  : std::decay<decltype(std::declval<T&>().*(&T::bar))>
  { };

这首先声明帮助器has_bar来回答类型是否具有嵌套成员的问题.该助手使用SFINAE获得真或假值.如果& T :: bar是一个有效的表达式,那么将使用test的第一个重载,它将返回true_type,因此value将被设置为true_type :: value,即true.否则,将选择回退重载并将值设置为false.

然后,enable_if_has_bar模板使用默认模板参数,该参数被推导为has_bar< T> :: value的值.当has_bar< T> :: value为false时,使用主模板.当has_bar< T> :: value为true时使用特化,在这种情况下,我们知道表达式& T :: bar是有效的,并且可以在decltype表达式中使用它来获取类型.

std :: decay用于转换int& decltype表达式的结果只是int.继承衰减比使用它来定义成员要短一些,这将是:

typedef typename std::decay<decltype(std::declval<T&>().*(&T::bar))>::type type;

我在未评估的表达式中使用了标准实用程序declval< T>(),它比static_cast< T *>(0)的类型更短,更具惯用性和表达性.

使用decay的另一种方法是从int T :: *类型获取int类型的另一个helper类型,例如

template<typename T>
  struct remove_class;
  { };

template<typename Member, typename Class>
  struct remove_class<Member Class::*>
  {
    typedef Member type;
  };

template<typename T>
  struct enable_if_has_bar<T, true>
  : remove_class<decltype(&T::bar)>
  { };

(名称remove_class不是很好,但基本上它需要指向数据成员类型的指针并给出成员的类型.)

标签:c,templates,sfinae
来源: https://codeday.me/bug/20190901/1782995.html