SFINAE确定类型是否具有潜在的重载方法 [英] SFINAE to determine if a type has a potentially overloaded method

查看:49
本文介绍了SFINAE确定类型是否具有潜在的重载方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在寻找SFINAE解决方案,以便在编译时检查类型是否具有方法.我的目标是检查类型是否为有效的鸭子类型" ,而不是无用的编译错误,我想使用 static_assert 提供信息.

I was looking for an SFINAE solution to check at compile time if a type has a method. My goal is to check if a type is a valid "duck type", but instead of a useless compile error, I want to use static_assert to provide an informative message.

我发现了[这个问题],它为我的问题提供了一个很好的答案,除了当类型为方法提供重载时失败:

I found [this question], which provides a fairly good answer to my problem, except it fails when the type provides overload to the method:

template<typename...> // parameter pack here
using void_t = void;

template<typename T, typename = void>
struct has_xxx : std::false_type {};

template<typename T>
struct has_xxx<T, void_t<decltype(&T::xxx)>> :
  std::is_member_function_pointer<decltype(&T::xxx)>{};

在下面的示例中可以很好地工作,并区分方法和成员变量:

This works fine with the following example, and differentiate method and member variable:

struct Foo { int xxx() {return 0;}; };
struct Foo2 {};
struct Foo3{ static double xxx;};
double Foo3::xxx = 42;

int main() {
   static_assert(has_xxx<Foo>::value, "");
   static_assert(!has_xxx<Foo2>::value, "");
   static_assert(!has_xxx<Foo3>::value, "");
}

原始实时演示

如果有过载,代码将失败:

The code fails if there is an overload:

struct Foo { int xxx() {return 0;}  void xxx(int){} };

int main() {
   static_assert(has_xxx<Foo>::value, "");
}

使用重载方法的实时演示失败

如何改进此代码以处理重载?

How can this code be improved to handle overloading?

推荐答案

正确的鸭子类型检查是是否可以使用特定的签名来调用您的 xxx ,并将其返回值用于特定的上下文中"". xxx 重载是没有用的,因为它的用法很重要.

A proper duck type check is "can your xxx be invoked with a specific signature, and its return value used in a certain context". Having an overloaded xxx is not useful, because it matters how it is used.

我们从 can_apply

namespace details {
  template<template<class...>class Z, class, class...>
  struct can_apply:std::false_type{};
  template<template<class...>class Z, class...Ts>
  struct can_apply<Z, std::void_t<Z<Ts...>>, Ts...>:
    std::true_type{};
}

template<template<class...>class Z, class...Ts>
using can_apply=details::can_apply<Z, void, Ts...>;

它告诉您给定的参数是否可以合法地传递给某些模板.

which tells you if given arguments can be legally passed to some template.

然后我们表达我们想要的鸭子类型:

We then express the duck type we want:

template<class T>
using xxx_result = decltype( std::declval<T>().xxx() );

template<class T>
using can_xxx = can_apply< xxx_result, T >;

can_xxx< T> 是真实的还是虚假的,取决于我们是否可以执行 t.xxx().

and can_xxx<T> is truthy or falsy depending on if we can do a t.xxx() or not.

如果我们想要类型限制,我们只需:

If we want a type restriction, we just:

template<class T, class R>
using xxx_result_as_R = decltype( R(std::declval<T>().xxx()) );
template<class T, class R>
using can_xxx_as_R = can_apply< xxx_result_as_R, T, R >;

因此,如果您希望 xxx 返回能够 int 的内容,我们将得到:

so if you want xxx to return something int-able, we get:

template<class T>
using valid_xxx = can_xxx_as_R<T, int>;

这篇关于SFINAE确定类型是否具有潜在的重载方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆