2015-04-03 2 views
12

При определенных условиях я хочу, чтобы SFINAE покинул конструктор копирования и скопировал оператор присваивания шаблона класса. Но если я это сделаю, создаются конструктор копии по умолчанию и оператор присваивания по умолчанию. SFINAE выполняется на основе тегов, которые я передаю как параметры шаблона класса. Проблема в том, что SFINAE работает только с шаблонами, а оператор-конструктор/присваивание копий не может быть шаблоном. Существует ли обходной путь?SFINAE прочь конструктор копирования

+7

Используйте базовый класс, который запрещает конструктор/назначение копии в зависимости от аргумента шаблона. – stefan

+0

Поскольку конструктор шаблонов не является конструктором копирования, он также не препятствует тому, чтобы конструктор копирования неявно был объявлен, что иногда будет предпочтительнее, чем ваш конструктор шаблонов, так что это похоже на тупик. Комментарий @ stefan кажется, что это сделало бы для хорошего ответа. – hvd

ответ

10

Это решение использует базовый класс, который условно не копируемыми (по явно маркировки конструктор копирования и копирующий оператор присваивания, как удаляется).

template <bool> 
struct NoCopy; 

template <> 
struct NoCopy<true> 
{ 
    // C++11 and later: marking as deleted. Pre-C++11, make the copy stuff private. 
    NoCopy(const NoCopy&) = delete; 
    NoCopy& operator=(const NoCopy&) = delete; 
    protected: 
     ~NoCopy() = default; // prevent delete from pointer-to-parent 
}; 

template <> 
struct NoCopy<false> 
{ 
    // Copies allowed in this case 
    protected: 
     ~NoCopy() = default; // prevent delete from pointer-to-parent 
}; 

Пример использования:

template <typename Number> 
struct Foo : NoCopy<std::is_integral<Number>::value> 
{ 
    Foo() : NoCopy<std::is_integral<Number>::value>{} 
    { 
    } 
}; 

int main() 
{ 
    Foo<double> a; 
    auto b = a; // compiles fine 
    Foo<int> f; 
    auto g = f; // fails! 
} 

Примечание: деструктор NoCopy объявляется protected, чтобы избежать виртуального наследования (спасибо за подсказку, @Yakk).

+0

Примечание: реализация Уолтера 'copyable' немного более элегантна (поскольку она специализируется только на специальном случае). Но очевидно, что оба подхода работают очень хорошо. – stefan

+0

'NoCopy' должен иметь защищенный деструктор в обоих случаях, так как это класс, который должен быть унаследован, и мы не хотим форсировать« виртуальные »служебные данные. Как вопрос качества реализации. – Yakk

+0

@Yakk Спасибо за комментарий. Я еще не знал об этой детали языка :) – stefan

6

Метод получения скрещиваемой или не скопируемой базы является стандартной идиомой для этого типа проблемы (см. Также комментарий Штефана). Один из способов его реализации, как это:

template<bool> struct copyable 
{ 
protected: 
    ~copyable() = default; 
}; 

template<> struct copyable<false> 
{ 
    copyable(copyable const&) = delete; 
    copyable&operator=(copyable const&) = delete; 
protected: 
    ~copyable() = default; 
}; 

template<bool allow_copy> 
class some_class : copyable<allow_copy> { /* ... */ }; 
+0

Да, это маршрут специализации. – user1095108

+1

@ user1095108 нет, это не маршрут специализации. он использует специализацию как деталь реализации, но он не состоит из специализации вашего 'some_class'. И fianlly, 'copyable' должен иметь' protected: ~ copyable() = default' в обоих случаях. – Yakk

+0

@Yakk Хорошо, я добавил защищенный деструктор. В чем смысл? Является ли он «копируемым» базовым классом? – Walter

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