【问题标题】:Implementation of std::is_function with cv-qualifiers and ref-qualifiers使用 cv-qualifiers 和 ref-qualifiers 实现 std::is_function
【发布时间】:2017-05-19 02:46:37
【问题描述】:

根据C++ reference,这是std::is_function 的有效实现(为简洁起见,不包括可变参数函数的部分特化和noexcept 说明符):

template<class>
struct is_function : std::false_type { };
 
// specialization for regular functions
template<class Ret, class... Args>
struct is_function<Ret(Args...)> : std::true_type {};
 
// specialization for function types that have cv-qualifiers
template<class Ret, class... Args>
struct is_function<Ret(Args...)const> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...)volatile> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...)const volatile> : std::true_type {};
 
// specialization for function types that have ref-qualifiers
template<class Ret, class... Args>
struct is_function<Ret(Args...) &> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...)const &> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...)volatile &> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...)const volatile &> : std::true_type {};
struct is_function<Ret(Args...) &&> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...)const &&> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...)volatile &&> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...)const volatile &&> : std::true_type {};

但是,在成员函数上使用std::is_function 会返回false

struct X
{
    int Test(float)
    {
        return 0;
    }
};

int main()
{
    auto x = std::is_function_v<decltype(&X::Test)>; // x is 'false'
    return 0;
}

据我了解,cv-qualifiers 和 ref-qualifiers 只适用于类成员函数。

所以我的问题是,为什么 std::is_function 的实现专门针对所有不同的 cv-qualifiers 和 ref-qualifiers 而不考虑成员函数“函数”?

更新:

根据下面的答案,我决定做一个实验。我实现了自己的最小版本std::is_function

template <class T>
struct IsFunction :
    std::integral_constant<bool, false>
{
};

template <class R, class... A>
struct IsFunction<R(A...)> :
    std::integral_constant<bool, true>
{
};

template <class T>
constexpr bool IsFunctionV = IsFunction<T>::value;

然后我改了X::Test的签名:

struct X
{
    int Test(float) const
    {
        return 0;
    }
};

使用答案中提供的function_traits 结构,然后我尝试了这个:

auto x = IsFunctionV<function_traits<decltype(&X::Test)>::type>;

在这种情况下,x 为假。但是,如果我将 const 的专业化添加到我的 IsFunction 中:

template <class R, class... A>
struct IsFunction<R(A...) const> :
    std::integral_constant<bool, true>
{
};

那么 x 将是 true!所以过载很重要。但我不确定我理解为什么,或者function_traits 最终如何将“成员函数指针”转换为“成员函数”,这与常规函数并不相同,是不是......?

【问题讨论】:

  • 这不是您要求的功能。您只匹配带有R(*)(Args...) 的函数,但成员函数实际上是R(C::*)(Args...) 类型。
  • 是的,我知道std::is_member_function_pointer 可用于检查成员函数。不过,不确定“这不是您要求的功能”是什么意思。调用 std::is_function_v&lt;decltype(&amp;X::Test)&gt; 计算结果为 false。这不是我的要求。这就是标准的行为方式。问题是为什么is_function 的标准实现专门针对成员函数限定符,无论如何它对成员函数的求值结果为 false,而不管限定符如何。
  • 它在哪里专门针对成员函数限定符?
  • 检查我上面粘贴的来自cppreference.com的有效实现的sn-p。 constvolatile 函数限定符,以及 &amp;&amp;&amp; 限定符,以及它们的所有组合都有一个专门化。

标签: c++ typetraits


【解决方案1】:

据我了解,cv-qualifiers 和 ref-qualifiers 只适用于类成员函数。

虽然非成员函数不能有 cv-qualifiers 或 ref-qualifiers,但函数类型仍然可以包含它们而无需绑定到特定的类类型。

typedef void fc() const;
struct S { fc f; };
void S::f() const { }

这里,std::is_function_v&lt;fc&gt; 应该是 true

【讨论】:

  • 这实际上解释了很多。我不知道 typedef 和定义这样的函数是合法的。我无法想到执行此类操作的实际用例,但至少它解释了为什么 std::is_function 是这样实现的。
【解决方案2】:

这不是问题的直接答案,而是说明如何从成员函数类型中删除类。


您可以通过简单的类型特征从成员函数中删除类实例,以使该函数与is_function 兼容。这显然是必要的,因为

std::function、lambdas、具有重载 operator() 的类和指向函数的指针等类型不计入函数类型。

http://en.cppreference.com/w/cpp/types/is_function

#include <iostream>
#include <type_traits>

template < typename T >
struct function_traits { typedef T type; };

template < typename T, typename C >
struct function_traits < T(C::*) > { typedef T type; };

struct X
{
    int Test(float)
    {
        return 0;
    }
};

int test(float) { return 1; }

int main()
{
    std::cout << std::boolalpha;

    auto x = std::is_function< decltype(&X::Test) >::value;
    std::cout << x << '\n';

    auto y = std::is_function< function_traits<decltype(&X::Test)>::type >::value;
    std::cout << y << '\n';

    auto z = std::is_function< function_traits<decltype(test)>::type >::value;
    std::cout << z << '\n';
}

Demo on Wandbox

【讨论】:

  • 虽然这是一个有趣的功能(我不知道你能做到这一点!),但它并不能完全回答问题。同样,我完全意识到std::is_function 不将 lambda、仿函数和指向函数的指针算作“函数类型”。我的问题是,如果成员函数是唯一可以具有 cv/ref 限定符的函数,并且成员函数不是“函数类型”,那么为什么 std::is_function 专门用于 cv/ref 限定符?
  • @Zeenobit 我相应地编辑了我的答案,但将其留在这里以供将来参考。
猜你喜欢
  • 1970-01-01
  • 2013-06-12
  • 2012-08-23
  • 2014-06-08
  • 1970-01-01
  • 1970-01-01
  • 2015-02-20
相关资源
最近更新 更多