2016-11-30 2 views
9

C++ 11's auto ключевое слово отлично.Есть ли способ отключить автоматическую декларацию для нестандартных типов?

Однако, по моему мнению, если тип Не Regular (смотри, например, What is a "Regular Type" in the context of move semantics?) использование auto становится сложнее.

Есть ли способ отключить объявление auto для такого типа?

Пусть один имеет ref класс, который эмулирует ссылку

double 5.; 
ref<double> rd = d; // `ref` behaves like a reference, so it is not a regular type 
ref<double> rd2 = rd; // `ref` can be (syntactically) copy constructible, (it is not regular for other reason) 
auto r = rd; // now r is not `double`, but EVEN WORST it is `ref<double>`. 

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

Единственный способ, которым я нашел auto r = rd не работать (дать ошибку компиляции), сделать класс несовместимым, однако мне нужен класс, чтобы иметь конструктор копирования (со специальной семантикой, но конструктор копирования еще).

Есть ли способ отключить синтаксис auto r = rd как-нибудь? когда decltype(rd) не является регулярным.

(Еще лучше может быть, чтобы как-то рассказать компилятору, что именно должно делать auto).

Примечание: Это не очень искусственная проблема, можно видеть, что этот тип проблемы лежит в основе std::vector<bool>::reference (который также является ссылочной оболочкой). Отключение (каким-то образом) синтаксиса auto b = v[10] не решит проблему std::vector<bool>, но это затруднит использование.

Я что-то упустил? Должен ли я изменить какую-то другую часть дизайна? В случае если нерегулярные классы имеют тип признака, который помог бы компилятор определить более общее авто (например, вывести bool для auto b = v[10] где std::vector<bool> v.)

+0

Добавляет 'static_assert', где вы назначаете возможность? – wasthishelpful

+0

@wasthishelpful, назначение не является проблемой, я могу реализовать семантику, которая мне нужна в 'operator =', или даже удалить ее. Проблема заключается в том, что этот синтаксис 'auto r = rd' позволяет разрешить его с неправильным значением (что на C++ невозможно изменить). Строка 'auto r = rd' не является назначением, а конструкцией с (неправильным) выводом типа. (более конкретно, для «ссылочного типа» это (или должна быть) операция привязки). – alfC

+0

Согласно http://www.cplusplus.com/reference/functional/reference_wrapper/, вы можете получить доступ к своему значению, вызвав 'ref.get()'. Построение из этого должно быть однозначным. –

ответ

3

Конструктор копирования означает, что вы ожидаете, что класс должен быть скопирован. auto x = y; делает копию y в x.

Если вы хотите получить супер-специальную копию, которую вы не хотите запускать автоматически, вы можете использовать прокси-объект.

template<class T> 
struct pseudo_copy; 

template<class T> 
struct pseudo_copy<T const&> { 
    T const& t; 
    // T const& can be initialized from T&&: 
    pseudo_copy(T const& tin):t(tin) {} 
    pseudo_copy(T&& tin):t(tin) {} 
    pseudo_copy(pseudo_copy const&)=delete; 
}; 
template<class T> 
struct pseudo_copy<T&&> { 
    T&& t; 
    pseudo_copy(T&& tin):t(std::move(tin)) {} 
    pseudo_copy(pseudo_copy const&)=delete; 
}; 
template<class T> 
pseudo_copy<T const&> pseudo(T& t) { return {t}; } 
template<class T> 
pseudo_copy<T&&> pseudo(T&& t) { return {t}; } 

struct strange { 
    strange(strange const&)=delete; 
    strange(pseudo_copy<strange const&>) {} // copy ctor 
    strange(pseudo_copy<strange&&>) {} // move ctor 
    strange()=default; 
}; 

теперь мы можем:

strange foo() { return pseudo(strange{}); } 

strange x = pseudo(foo()); 

и теперь любая попытка скопировать strangeсусло к через вызов pseudo и использование auto никогда законным, потому что ничто не имеет конструктор копирования.

Вы также можете сделать конструктор копирования закрытым и использовать его для реализации конструктора копии psuedo.


Обратите внимание, что значение copy/move ctor ограничено правилами элиции на C++.


В C++ типа класса вычетов 17 шаблона может сделать:

template<class T> 
struct value{ 
    value_type_of<T> v; 
    value(T in):v(std::forward<T>(in)){} 
}; 

int x= 3; 
value a = std::ref(x); 

И a.v бы int.

+0

Ну, я не согласен, копируемо-конструктивный должен означать, что по крайней мере это верно. 'Decltype (y) x = y' является действительным и имеет некоторое значение. 'auto x = y' семантически отличается, потому что в общем коде каждый ожидает, что' x' будет иметь семантику значений, даже если 'y' нет. Я просто говорю, что 'auto', по-видимому, слишком ограничительный. Жаль, что для действительно общего кода нужно было бы что-то вроде 'typename value_rep_of :: type x = y;'. Где 'value_rep' является признаком (тривиально для большинства случаев, за исключением нерегулярных типов). – alfC

+1

@alfc Может быть помощь в выводе типа конструктора шаблона в C++ 17, если вы принимаете обертку. Поэтому 'value a = b;' где 'value ' - это шаблон, который сохраняет значение в поле внутри себя. – Yakk

+0

Хороший момент, я должен изучить это. Это очень многообещающе, потому что он скрывает/абстрагирует ваш взлом. – alfC

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