标准说如果没人能分辨出来,你就可以逃脱。而且你无法合法地创建一个PTMF到forward_list
,这样你就很安全。
自定义分配器的危险已经被指出。但即使对于std::allocator<T>
,也存在某个人可能专注于std::allocator<MyType>
然后检测到allocator::construct/destroy
未被调用的危险。
好的,但可以专门说std::forward_list<int>
(没有自定义分配器,没有用户定义的value_type),并使insert_after
静态?
不可以。使用新的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);
}
的运行程序,并打印出:
not static
但是,如果我做insert_after
静:
static iterator insert_after(const_iterator p, const T& x);
然后我得到一个编译时错误:
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.
检测到差异。
因此它是不符合使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();
}
现在测试将显示出无论是“静态”或“不是静态的”,这取决于insert_after
成员函数是静态的还是没有。
变异列表操作需要访问列表的分配器,所以我怀疑它们可能是静态的(特别是对于新的有状态分配器)。 –
尽管如此,模板可以专门用于'std :: allocator'这个非常常见的情况,如果需要的话,用户也可以自己选择。 – Potatoswatter
你会如何根据关于* iterator *的知识来专门做这件事?迭代器不知道它属于哪个列表,也不知道该列表使用哪个分配器。 –