Стандарт гласит, что с этим можно обойтись, если никто не скажет разницу. И вы правы, что нельзя легально создать PTMF в forward_list
, так что вы в безопасности таким образом.
Опасность пользовательских распределителей уже указана. Но даже для std::allocator<T>
существует опасность, что кто-то может специализироваться std::allocator<MyType>
и затем обнаружить, что allocator::construct/destroy
не вызывается.
Хорошо, но можно специализироваться, скажем std::forward_list<int>
(нет пользовательского распределителя, нет определенного пользователем значения_типа) и сделать 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
или нет.