2011-01-28 2 views
6

В следующем 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* код компилируется из-за разрешения перегрузки, предпочитающего первый шаблон функции в этом случае. Но это побеждает цель иметь выражение как часть объявления функции. Цель состоит в том, чтобы заставить компилятор вытолкнуть функцию из разрешения перегрузки, установленного в случае ошибки.

+0

Я бы взял аргумент «выбор» по ссылке, так как наследование задействовано. Не то чтобы это решило вашу проблему ... –

+0

@Matthieu: по ссылке не требуется, чтобы этот тег отправлял работу. Правило разрешения частичной упорядочивания по-прежнему применяется. Я не проверял, как это оптимизируется компилятором, но libstdC++ также использует диспетчер тегов без ссылок на реализацию std :: advance, например. – sellibitze

+0

Я знаю, что это не требуется, я бы по-прежнему делал это по привычке, я думаю, чтобы избежать нарезки объекта (не для того, чтобы тег должен иметь какие-либо данные/методы ...) –

ответ

1

Я думаю, что я убедил себя, что это на самом деле ошибка компилятора и подала report. Давай посмотрим что происходит. В качестве обходного пути decltype(new T(*ptr)) можно заменить на T*. Единственное отличие состоит в том, что шаблон функции останется частью набора разрешений перегрузки, который в этом случае не является большой проблемой.

Редактировать: Кстати, мне сказали, что clang ++ принимает приведенный выше код.

1

У меня была очень похожая проблема с MSVC, и выяснилось, что компилятор не узнает мои типы возвращаемых вариантов совместного использования в виртуальной функции. Попробуйте изменить определение derived клона на возврат abc.

+0

Это не поможет. 'производный' не является абстрактным. Я даже создаю объект типа 'производный' в основной функции. – sellibitze

Смежные вопросы