Pot*_*ter 9 c++ c++-standard-library c++11
std::forward_list提供可能不需要实际访问该对象的成员insert_after和erase_after成员std::forward_list.因此,它们可以作为static成员函数实现,并且可以在没有列表对象的情况下调用 - 对于想要从列表中删除自身的对象很有用,这是一种非常常见的用法.编辑:此优化仅适用于forward_list特殊化std::allocator或用户定义的无状态分配器.
符合标准的实现可以做到这一点吗?
§17.6.5.5/ 3说
对C++标准库中描述的成员函数签名的调用就好像实现没有声明其他成员函数签名一样.
用脚注
有效的C++程序始终调用期望的库成员函数或具有等效行为的函数.实现还可以定义其他成员函数,否则这些函数将不会被有效的C++程序调用.
我不清楚添加是否static会创建一个"不同的"成员函数,但删除(隐式)参数不应该破坏任何添加默认参数的东西,这是合法的.(您不能合法地将PTMF带到任何标准成员函数.)
我觉得应该允许图书馆这样做,但我不确定是否会破坏某些规则.列出的成员函数原型如何规范?
该标准表示,如果没有人能说出差异,你就可以逃脱它.而你是正确的,不能合法创建一个PTMF forward_list,所以你这样安全.
已经指出了定制分配器的危险.但即使是std::allocator<T>存在某种危险,即某人可以专攻std::allocator<MyType>并随后发现allocator::construct/destroy没有被召唤.
好的,但是可以专门说一下std::forward_list<int>(没有自定义分配器,没有用户定义的value_type)和make insert_afterstatic?
不会.使用新的SFINAE功能可以检测到这种变化.这是一个演示:
#include <memory>
#include <iostream>
template <class T, class A = std::allocator<T>>
class forward_list
{
public:
typedef T value_type;
struct const_iterator {};
struct iterator {};
iterator insert_after(const_iterator p, const T& x);
};
template <class C>
auto test(C& c, typename C::const_iterator p, const typename C::value_type& x)
-> decltype(C::insert_after(p, x))
{
std::cout << "static\n";
return typename C::iterator();
}
template <class C>
auto test(C& c, typename C::const_iterator p, const typename C::value_type& x)
-> decltype(c.insert_after(p, x))
{
std::cout << "not static\n";
return typename C::iterator();
}
int main()
{
::forward_list<int> c;
test(c, ::forward_list<int>::const_iterator(), 0);
}
Run Code Online (Sandbox Code Playgroud)
该程序运行并打印出来:
not static
Run Code Online (Sandbox Code Playgroud)
但如果我做insert_after静态:
static iterator insert_after(const_iterator p, const T& x);
Run Code Online (Sandbox Code Playgroud)
然后我得到一个编译时错误:
test.cpp:34:5: error: call to 'test' is ambiguous
test(c, ::forward_list<int>::const_iterator(), 0);
^~~~
test.cpp:16:6: note: candidate function [with C = forward_list<int, std::__1::allocator<int> >]
auto test(C& c, typename C::const_iterator p, const typename C::value_type& x)
^
test.cpp:24:6: note: candidate function [with C = forward_list<int, std::__1::allocator<int> >]
auto test(C& c, typename C::const_iterator p, const typename C::value_type& x)
^
1 error generated.
Run Code Online (Sandbox Code Playgroud)
检测到差异.
因此,它不符合制作forward_list::insert_after静态.
更新
如果你想让"静态"过载可调用,你只需要使它比"非静态"过载更令人满意.一种方法是将"非静态"重载更改为:
template <class C, class ...Args>
auto test(C& c, typename C::const_iterator p, const typename C::value_type& x, Args...)
-> decltype(c.insert_after(p, x))
{
std::cout << "not static\n";
return typename C::iterator();
}
Run Code Online (Sandbox Code Playgroud)
现在测试将打印出"静态"或"非静态",具体取决于insert_after成员函数是否为静态.