摆脱 C++ 中令人讨厌的函数类型的可能方法?

Nik*_*dig 2 c++ templates metaprogramming function function-qualifier

所以我最近接触到了C++中所谓的“令人厌恶的函数类型”的怪诞(据我所知源自这篇论文:https ://www.open-std.org/jtc1/sc22/wg21/文档/论文/2015/p0172r0.html)。我想了一会儿,它似乎确实有一定的道理,但如果有人以某种方式将它们从语言中完全删除,一切都会变得更加干净和更令人满意。

也许还有其他来源,但是(至少对我来说)令人讨厌的函数类型的大多数问题都来自于处理成员函数。如果我想获取成员函数的类型,我会这样做:

template <typename T>
struct remove_ptr_to_member { using type = T; };

template <typename T, typename class_t>
struct remove_ptr_to_member<T class_t::*> { using type = T; };

struct container {
   void func() const;
};

using member_function_type = typename remove_ptr_to_member<decltype(container::func)>::type;
Run Code Online (Sandbox Code Playgroud)

const由于的声明中存在 a func(),删除指向成员的指针部分会给我们留下一个令人讨厌的函数。

this如果将不可见参数放入成员函数的类型中,则可以避免这种情况。然后,通常会导致令人讨厌的函数的东西都将应用于参数thisconst意味着一个const this指针,&&意味着对 实例的右值引用this,等等......)。

现在,即使删除类型的指向成员的指针部分,剩下的也只是完全正常的函数类型。这样做的好处是,它会减少您在实现诸如is_function.

经典方法:

// primary template
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 variadic functions such as std::printf
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 {};
// etc... (goes on for a while)
Run Code Online (Sandbox Code Playgroud)

新方法:

// primary template
template <typename>
struct is_function : std::false_type { };

// specialization for regular functions
template<typename Ret, typname... Args>
struct is_function<Ret(Args...)> : std::true_type { };

// specialization for variadic functions such as std::printf
template<typename Ret, typname... Args>
struct is_function<Ret(Args......)> : std::true_type { };

// same thing but with noexcept
template<typename Ret, typname... Args>
struct is_function<Ret(Args...) noexcept> : std::true_type { };
template<typename Ret, typname... Args>
struct is_function<Ret(Args......) noexcept> : std::true_type { };
Run Code Online (Sandbox Code Playgroud)

就这样了。不需要很长的样板,因为所有复杂的事情(constvolatile等...)都隐藏在第一个参数中。

我很抱歉等了这么久才提出实际问题,但时间已经到了:有人对此修复有反驳意见吗?它甚至是一个修复程序,也许它不能处理所有需要处理的事情?我想我想知道的是,为什么这不在标准中?如果这是一个好主意,一定有人想到了,对吗?一定有一些我没有考虑到的额外信息,因为这看起来太简单了。

use*_*522 5

几乎正是您所建议的内容已被 C++23 接受为具有显式对象参数的成员函数,如下所示:

struct container {
    void func(this container const&);
};
Run Code Online (Sandbox Code Playgroud)

该函数的类型 thenvoid(container const&)代替或等效地willvoid() const的类型代替。&container::funcvoid(*)(container const&)void (container::*)() const

请参阅P0847,其中介绍了此新功能。

但这不会改变具有隐式而不是显式对象参数的旧式非静态成员函数需要具有 cvref 限定的函数类型。更改这些函数的类型会破坏大量代码,因此为时已晚。