2016-11-30 10 views
9

Słowo kluczowe w C++ 11: auto jest świetne.Czy istnieje sposób na wyłączenie automatycznej deklaracji dla nieregularnych typów?

Jednak moim zdaniem, jeśli typ jest nieregularny (patrz na przykład What is a "Regular Type" in the context of move semantics?) wykorzystanie auto staje się trudne.

Czy istnieje sposób wyłączenia deklaracji auto dla tego typu?

Załóżmy jeden ma ref klasy, która emuluje odniesienie

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>`. 

(w prawdziwym życiu byłoby bardziej skomplikowane klasy, ważne jest to, że klasa pod ręką nie jest regularny.)

Jedyny sposób, w jaki znalazłem auto r = rd nie działać (podać błąd kompilacji) jest spowodowanie, że klasa nie może być kopiowana, jednak potrzebuję klasy, aby mieć konstruktora kopii (ze specjalną semantyką, ale wciąż konstruktor kopii).

Czy jest jakiś sposób wyłączenia składni auto r = rd w jakiś sposób? gdy decltype(rd) nie jest regularny.

(Jeszcze lepiej byłoby móc w jakiś sposób powiedzieć kompilatorowi, co dokładnie powinien zrobić auto).

Uwaga: nie jest to bardzo sztuczny problem, można zauważyć, że ten typ problemu jest rdzeniem std::vector<bool>::reference (który jest również opakowaniem referencyjnym). Wyłączenie (w jakiś sposób) składni auto b = v[10] nie rozwiąże problemu z std::vector<bool>, ale utrudni to nieprawidłowe użycie.

Czy brakuje mi czegoś? Czy powinienem zmienić inną część projektu? Gdyby nie regularne zajęcia mają typ cechę, która pomogłaby kompilator określić bardziej ogólne Auto (na przykład wyprowadzić bool dla auto b = v[10] gdzie std::vector<bool> v.)

+0

Czy dodajesz 'static_assert', do którego przypisujesz możliwość? – wasthishelpful

+0

@wasthishelpful, zadanie nie stanowi problemu, mogę zaimplementować semantykę potrzebną w 'operator =', lub nawet ją usunąć. Problem polega na tym, że pozwala to na składnię 'auto r = rd' i pozwala na jej niewłaściwe znaczenie (co wydaje się niemożliwe do zmiany w C++). Wiersz 'auto r = rd' nie jest przypisaniem, ale konstrukcją z (błędnym) odjęciem typu. (bardziej szczegółowo, dla "typu referencyjnego" jest (lub powinna być) operacją wiążącą). – alfC

+0

Zgodnie z http://www.cplusplus.com/reference/functional/reference_wrapper/ możesz uzyskać dostęp do swojej wartości, wywołując 'ref.get()'. Konstruowanie z tego powinno być jednoznaczne. –

Odpowiedz

3

Konstruktor kopia oznacza, że ​​oczekują, że klasa ma zostać skopiowany. auto x = y; wykonuje kopię y w x.

Jeśli chcesz super-specjalną kopię, której nie chcesz uruchamiać automatycznie, możesz użyć obiektu proxy.

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; 
}; 

teraz możemy:

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

strange x = pseudo(foo()); 

i teraz każda próba skopiowania strangemoszczu na drodze zaproszenia do pseudo i wykorzystanie auto nigdy nie jest legalne, ponieważ nic nie ma konstruktora kopii.

Można również ustawić konstruktora kopiowania jako prywatny i użyć go do implementacji konstruktora kopii psuedo.


Zwróć uwagę, że znaczenie copu kopiowania/przenoszenia jest ograniczone regułami elizacji w C++.


w C++ 17 szablonów typu klasa odliczenia mogłoby:

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); 

I a.v byłoby int.

+0

Cóż, nie zgadzam się, kopiowanie-konstruktywne powinno oznaczać, że przynajmniej to jest ważne "decltype (y) x = y" jest poprawne i ma pewne znaczenie. 'auto x = y' jest semantycznie odmienne, ponieważ w kodzie ogólnym oczekuje się, że' x' będzie miał semantykę wartości, nawet jeśli 'y' nie. Mówię tylko, że "auto" najwyraźniej jest zbyt restrykcyjne. Szkoda, że ​​dla prawdziwie generycznego kodu trzeba by coś zrobić, jak 'typename value_rep_of :: type x = y;'. Gdzie 'value_rep' jest cechą (w większości przypadków trywialne, z wyjątkiem typów nieregularnych). – alfC

+1

Przydaje się pomoc przy odliczaniu typu konstruktora szablonu w C++ 17, jeśli akceptujesz opakowanie. Zatem 'value a = b;', gdzie 'wartość ' jest szablonem, który przechowuje wartość w polu w sobie. – Yakk

+0

Dobra uwaga, muszę się nad tym zastanowić. To bardzo obiecujące, ponieważ ukrywa/streszcza hack. – alfC

Powiązane problemy