В следующем C++ 0x кода я попытался клонировать объект с помощью функции-члена в клон (если он существует) и падает обратно на копию конструктор:Искомый код C++ 0x или ошибка компилятора?
struct use_copy_ctor {};
struct prefer_clone_func : use_copy_ctor {};
template<class T>
auto clone(T const* ptr, prefer_clone_func)
-> decltype(ptr->clone())
{ return ptr->clone(); }
template<class T>
auto clone(T const* ptr, use_copy_ctor)
-> decltype(new T(*ptr))
{ return new T(*ptr); }
struct abc {
virtual ~abc() {}
virtual abc* clone() const =0;
};
struct derived : abc
{
derived* clone() const { return new derived(*this); }
};
int main()
{
derived d;
abc* p = &d;
abc* q = clone(p,prefer_clone_func());
delete q;
}
Идея заключается в том, чтобы использовать авто ...-> decltype (expr) для отсеивания неправильно сформированных выражений как часть вывода аргумента шаблона (SFINAE) и до разрешить возможную двусмысленность между шаблонами функций клонирования с помощью частичного заказа по адресу второй параметр функции.
К сожалению, GCC 4.5.1 не принимает эту программу:
test.cpp: In function 'int main()':
test.cpp:28:39: error: cannot allocate an object of abstract type
'abc'
test.cpp:14:12: note: because the following virtual functions are
pure within 'abc':
test.cpp:16:16: note: virtual abc* abc::clone() const
test.cpp:28:39: error: cannot allocate an object of abstract type
'abc'
test.cpp:14:12: note: since type 'abc' has pure virtual functions
Теперь вопрос в том, является ли это ошибка компилятора или я был неправильно считать, что SFINAE применяется здесь? Я был бы признателен за ответ с твердой аргументацией.
Edit: Если изменить decltype(new T(*ptr))
в T*
код компилируется из-за разрешения перегрузки, предпочитающего первый шаблон функции в этом случае. Но это побеждает цель иметь выражение как часть объявления функции. Цель состоит в том, чтобы заставить компилятор вытолкнуть функцию из разрешения перегрузки, установленного в случае ошибки.
Я бы взял аргумент «выбор» по ссылке, так как наследование задействовано. Не то чтобы это решило вашу проблему ... –
@Matthieu: по ссылке не требуется, чтобы этот тег отправлял работу. Правило разрешения частичной упорядочивания по-прежнему применяется. Я не проверял, как это оптимизируется компилятором, но libstdC++ также использует диспетчер тегов без ссылок на реализацию std :: advance, например. – sellibitze
Я знаю, что это не требуется, я бы по-прежнему делал это по привычке, я думаю, чтобы избежать нарезки объекта (не для того, чтобы тег должен иметь какие-либо данные/методы ...) –