2011-10-19 41 views
9

std::forward_list提供了insert_aftererase_after成员,这些成员可能不需要实际访问std::forward_list对象。因此它们可以作为static成员函数实现,并在没有列表对象的情况下被调用 - 对于想要从列表中删除自己的对象很有用,这是非常常见的用法。 编辑:这种优化只适用于专业std::allocator或用户定义的无状态分配器。std :: forward_list成员是否可以实现为静态?

符合标准的实现可以执行此操作吗?

§17.6.5.5/ 3表示

A call to a member function signature described in the C++ standard library behaves as if the implementation declares no additional member function signatures.

用脚注

A valid C++ program always calls the expected library member function, or one with equivalent behavior. An implementation may also define additional member functions that would otherwise not be called by a valid C++ program.

目前还不清楚我是否加入static将创建一个 “与众不同” 的成员函数,但除去(隐)论证不应该违反任何添加违约论据的东西,而这是合法的。 (你不能合法地将PTMF带到任何标准成员函数中。)

它让我觉得图书馆应该被允许这样做,但我不确定是否会破坏某些规则。列出的成员函数原型的规范性如何?

+3

变异列表操作需要访问列表的分配器,所以我怀疑它们可能是静态的(特别是对于新的有状态分配器)。 –

+0

尽管如此,模板可以专门用于'std :: allocator'这个非常常见的情况,如果需要的话,用户也可以自己选择。 – Potatoswatter

+0

你会如何根据关于* iterator *的知识来专门做这件事?迭代器不知道它属于哪个列表,也不知道该列表使用哪个分配器。 –

回答

9

标准说如果没人能分辨出来,你就可以逃脱。而且你无法合法地创建一个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成员函数是静态的还是没有。

+0

没想过用户专用的'std :: allocator',好点。但是,不是''静态''重载一个模板而没有可能的良好专业化,因此不合格,不需要诊断? – Potatoswatter

+0

更新答案与全功能“静态检测器”。 –

+0

好的...不是很难,但是这与如何通过找到一个非重载成员函数的类型来检测默认参数有什么不同?现在模板生成一个有效的特化,但它似乎仍然是UB,因为表达式'C :: insert_after()'没有被标准定义。同样,C++ 03中'Allocator :: construct'不兼容的可变模板实现是因为它可以被称为'construct <>(...)'?对于图书馆规范的深度,这确实是原始问题的焦点。 – Potatoswatter

相关问题