2015-01-22 2 views
11

Was ist das erwartete Ergebnis für std::is_constructible auf einem Typ mit einem privaten oder geschützten Destruktor?Std :: is_constructible auf Typ mit nicht öffentlichen Destruktor

Zum Beispiel kann ich noch einmal ein solches Objekt auf dem Heap konstruieren, obwohl nur ein Freund kann es kostenlos:

#include <type_traits> 

class Foo 
{ 
    friend void freeFoo(Foo*); 
public: 
    Foo() 
    {} 
private: 
    // Destructor is private! 
    ~Foo() 
    {} 
}; 

void freeFoo(Foo* f) 
{ 
    delete f; // deleting a foo is fine here because of friendship 
} 

int main() 
{ 
    Foo* f = new Foo(); 
    // delete f; // won't compile: ~Foo is private 
    freeFoo(f); // fine because of friendship 


    if(!std::is_constructible<Foo>::value) 
    { 
     std::cout << "is_constructible failed" << std::endl; 
    } 
} 

Die Endprüfung für is_constructible sowohl auf gcc und Visual C fehl ++ (gcc demo on coliru).

Ist das das erforderliche Verhalten nach dem Standard? Wenn ja, gibt es eine Möglichkeit zu überprüfen, ob der Typ einen bestimmten Konstruktor hat, unabhängig von der Zugriffsspezifikation für den Destruktor?

+0

In Verbindung stehend: https://groups.google.com/a/isocpp.org/forum/#!topic/std-discussion/bPwd3UkZa6w – Caramiriel

+0

@Caramiriel Leider adressiert es nicht direkt das Problem. 'is_destructible' hängt explizit von der Erreichbarkeit des Destruktors ab, was hier nicht der Fall ist. – Columbo

Antwort

12

Die C++ 14 FD definiert is_constructible wie folgt:

folgende Funktionsdeklaration Gegeben:

template <class T> 
add_rvalue_reference_t<T> create() noexcept; 

das Prädikat Bedingung für eine Template-Spezialisierung is_constructible<T, Args...> erfüllt, wenn und nur dann, wenn Die folgende Variablendefinition wäre für einige erfundene Variable t:

wohlgeformt 10
T t(create<Args>()...); 

Zugriffskontrolle ist, als ob in einem Kontext, in keinem Zusammenhang mit T und mit einem der Args durchgeführt. Nur die Gültigkeit des unmittelbaren Kontextes von der Variableninitialisierung wird berücksichtigt. [ Hinweis: Die Auswertung der Initialisierung in Nebenwirkungen wie die Instanziierung der Klasse Vorlage Spezialisierungen und Funktionsschablone Spezialisierungen, die Erzeugung von implizit definierte Funktionen und so weiter führen kann. Solche Nebenwirkungen sind nicht im "unmittelbaren Kontext" und können dazu führen, dass das Programm schlecht ausgebildet ist. -Ende note]

Verringert nun die Frage im Wesentlichen zu „Ist die Destruktoraufrufs im unmittelbaren Kontext der Variableninitialisierung?“ [Klasse.dtor]/11:

wird implizit A destructor

  • aufgerufen für ein konstruiertes Objekt mit statischer Speicherdauer (3.7.1) bei Programmende (3.6.3),
  • für einen konstruierte Objekt mit automatischer Speicherdauer (3.7.3), wenn der Baustein, in dem ein Objekt erstellt wird, für ein aufgebautes temporäres Objekt (12.2) endet (6.7),
  • .

In jedem Fall ist der Kontext des Aufrufs der Kontext der Konstruktion des Objekts.

So ist der destructor Aufruf ist im Zusammenhang mit dem Bau (was vermutlich auch ist hier die Initialisierung), was bedeutet, dass es in Betracht gezogen wird, und bewirkt, dass das Merkmal false zurückzukehren.
Ich glaube, dass dies unterspezifiziert ist (z. B. sofortige vs nicht explizit-unmittelbaren Kontext?), Aber intuitiv erwarte ich eine konforme Implementierung, um den Ausdruck als schlecht gebildet - entweder SFINAE-freundlich oder nicht (vorzugsweise ersteres). Aber nie gut geformt.
Clang with libc++, libstdc++ and GCC do say that it's invalid, SFINAE-friendly.


Wenn ja, ist es eine Möglichkeit zu überprüfen, ob der Typ einen bestimmten Konstruktor hat, unabhängig von den Zugriffsbezeichner auf dem destructor?

Wie wäre es mit new?

template <typename T, typename... Args> 
class is_only_constructible 
{ 
    template <typename, typename=void> struct test : std::false_type {}; 
    template <typename U> 
    struct test<U, decltype(void(new U(std::declval<Args>()...)))> : std::true_type {}; 

public: 
    static constexpr bool value = test<T>::value; 
}; 

Demo. Konsistente Merkmale können leicht festgestellt werden: Nehmen Sie das is_only_constructible Merkmal und kombinieren Sie es mit is_destructible (deutlich Letzteres gibt false in Kombination mit privaten Destruktoren).

+0

Ich frage mich: Wenn die Absicht des Komitees wäre, _is_constructible :: value' yield 'true' zu ​​haben, selbst wenn' T's Destruktor unzugänglich ist (was zu sein scheint, was Sie behaupten), warum geben Sie das nicht an Trait Verhalten in Bezug auf einen "neuen" Ausdruck? –

+0

@AndyProwl Das ist nicht was ich meine.Ich denke, das Komitee hat diesen Fall nicht richtig berücksichtigt, und daher ist der Text unterspezifiziert. – Columbo

+0

Ich verstehe. Ich habe diese Aussage dann wohl missverstanden: "Soweit ich sehen kann, befindet sich ein Destruktor-Aufruf nicht im unmittelbaren Kontext der Initialisierung und sollte daher nicht berücksichtigt werden". –

5

Zitiert Absatz [meta.unary.prop]/7 von dem C++ Standard (Draft N4296):

Bei der folgenden Funktionsdeklaration:

template <class T> 
add_rvalue_reference_t<T> create() noexcept; 

das Prädikat Bedingung für eine Template-Spezialisierung is_constructible<T, Args...> ist erfüllt, wenn und nur dann, wenn die folgende Variablendefinition für einige erfundene Variablen t:

T t(create<Args>()...); 
wohlgeformt wäre

Mit anderen Worten, is_constructible<T, Args...>::value ergibt false, wenn der Destruktor nicht zugänglich ist.

+0

Also, was ist mit dem zweiten Teil der Frage: Gibt es eine Möglichkeit zu überprüfen, ob der Typ einen bestimmten Konstruktor hat, unabhängig von der Zugriffsspezifizierer auf den Destruktor? – ComicSansMS

+0

@ComicSansMS: Ich fürchte, ich kann diesen Teil nicht beantworten (zumindest nicht von oben), obwohl ich vermute, dass die Antwort "nein" ist. –

+0

Das war, wovor ich Angst hatte. Die Überprüfung der Existenz einer gewöhnlichen Elementfunktion ist nicht so schwierig, aber Konstruktoren sind schwierig. Ich denke, das könnte als ein Versehen in 'type_traits' angesehen werden. – ComicSansMS

Verwandte Themen