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

标签 c++ function templates metaprogramming function-qualifier

所以我最近接触到了C++中所谓“令人厌恶的函数类型”的怪诞之处(据我所知源自这篇论文: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/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;

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

如果将不可见的 this 参数放入成员函数的类型中,就可以避免这种情况。然后,通常会导致令人讨厌的函数的东西都将被应用于 this 参数(const 意味着一个 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)

新方法:

// 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 { };

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

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

最佳答案

几乎完全符合您的建议,C++23 已接受作为具有显式对象参数的成员函数,如下所示:

struct container {
    void func(this container const&);
};

此函数的类型为 void(container const&) 而不是 void() const 或等效于 &container::func 的类型> 将是 void(*)(container const&) 而不是 void (container::*)() const

参见P0847引入了这个新功能。

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

关于c++ - 摆脱 C++ 中令人讨厌的函数类型的可能方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73178604/

相关文章:

c++ - 纯虚函数可以作为Variadic函数模板吗?

C++ 由模板参数固定的函数参数数量

c++ - 模板和 ODR

c++ - 正确地将有符号转换为无符号

c++ - 查找数组中的最小数字

Matlab函数参数传递

excel - 如何从 VBA 函数返回结果

c++ - Boost 堆栈跟踪不显示函数名称和行号

c++ - 如何修复递归 Flood Fill 段错误?

objective-c - Objective C - 如何向现有类添加方法?