c++ 'std::is_const'如何在非静态成员方法类型上工作?

yrdbyhpb  于 2022-11-27  发布在  其他
关注(0)|答案(2)|浏览(63)

问题:

std::is_const如何处理非静态成员方法类型?const成员方法不是常量限定类型吗?

范例:

class D {};

我们将拥有

std::is_const_v<void (D::*)() const> == false

跟进:

是否可以确定成员非静态方法的常量(在编译/运行时)?

jjjwad0x

jjjwad0x1#

我不认为有一个标准的特征来检查这种类型的稳定性,但它是一个相对直接的写:

#include <type_traits>

// Base template
template<class T>
struct is_const_member_func_ptr;

// Specialize for pointers to non-const member function
template<class T, class C, class ... A>
struct is_const_member_func_ptr<T (C::*)(A...)> : std::false_type {};

// Specialize for pointers to const member function
template<class T, class C, class ... A>
struct is_const_member_func_ptr<T (C::*)(A...) const> : std::true_type {};

// Convenient constant template
template<class T>
inline constexpr bool is_const_member_func_ptr_v = is_const_member_func_ptr<T>::value;

用法:

class D {};

static_assert(is_const_member_func_ptr_v<void (D::*)() const> == true);
static_assert(is_const_member_func_ptr_v<void (D::*)()>       == false);

示例:https://godbolt.org/z/Y9EjY5jzf
编辑:使用实际定义的成员函数的示例

// Usage
#include <iomanip>
#include <iostream>

class D 
{
public:
    void foo() {}
    void foo_c() const {}
};

int main()
{
    std::cout << std::boolalpha << is_const_member_func_ptr_v<decltype(&D::foo)> << '\n';
    std::cout << std::boolalpha << is_const_member_func_ptr_v<decltype(&D::foo_c)> << '\n';
}

实时:https://godbolt.org/z/9fvYs834W

f1tvaqid

f1tvaqid2#

在C++中,函数不是一等公民:不能有函数类型的对象(可以有函数对象,但这是不同的概念)。
void (D::*)() const是一个指针类型。std::is_const将告诉您指针是否为常量,因此:

  • std::is_const_v<void (D::*)() const> == false ;
  • std::is_const_v<void (D::* const)()> == true .

没有标准的特征来检查一个成员函数是否有const限定符。然而,你可以自己做。François Andrieux的答案是做这个的传统方法,但是正如在评论中提到的,你需要48个专门化来完成它。
下面是另一种也许更简洁的方式:

#include <type_traits>

struct ArbitraryType {
    template <typename T>
    operator T & ();
    template <typename T>
    operator T && ();
};

template<bool, bool, class T, class Arg, class... Args>
struct is_invocable_with_const_first_arg_impl : std::bool_constant<
    is_invocable_with_const_first_arg_impl<
        std::is_invocable_v<T, Arg const&, Args...> || std::is_invocable_v<T, Arg const&&, Args...>,
        std::is_invocable_v<T, Arg&, Args...> || std::is_invocable_v<T, Arg&&, Args...>,
        T, Arg, Args..., ArbitraryType
    >::value
> {};

template<bool b, class T, class Arg, class... Args>
struct is_invocable_with_const_first_arg_impl<true, b, T, Arg, Args...> : std::true_type {};

template<class T, class Arg, class... Args>
struct is_invocable_with_const_first_arg_impl<false, true, T, Arg, Args...> : std::false_type {};

template<class T, class Arg>
struct is_invocable_with_const_first_arg : is_invocable_with_const_first_arg_impl<false, false, T, Arg> {};

template<class T, class Arg>
inline constexpr bool is_invocable_with_const_first_arg_v = is_invocable_with_const_first_arg<T, Arg>::value;

template<class T>
struct is_const_member_func_ptr;

template<class R, class C>
struct is_const_member_func_ptr<R C::*> : std::bool_constant<
    is_invocable_with_const_first_arg_v<R C::*, C>
    || is_invocable_with_const_first_arg_v<R C::*, C>
> {};

template<class T>
inline constexpr bool is_const_member_func_ptr_v = is_const_member_func_ptr<T>::value;

Demo

相关问题