2016-07-10 3 views
2

Um ähnliche Funktionsdefinitionen zu wiederholen, verwende ich die Tatsache, dass die Mitglieder mit dem gleichen Namen vererbt werden versteckt und können ausgewählt werden/differenziert durch eine bestimmte Basisklasse-Qualifikation mit:Wie kann ich noexcept verwenden, wenn ich eine bestimmte versteckte Funktion aus meiner Vererbungsliste auswähle?

#include <type_traits> 

template<template<class, class> class CreatePolicy, class Base, class... Derived> 
class factory : public CreatePolicy<Base, Derived>... 
{ 
public: 
    template 
    < 
     class T, 
     std::enable_if_t 
     < 
      !std::is_same<Base, T>::value && std::is_base_of<Base, T>::value, int 
     > = 0 
    > 
    std::unique_ptr<Base> create() noexcept(noexcept(CreatePolicy<Base, T>::create())) 
    { 
     return CreatePolicy<Base, T>::create(); 
    } 
}; 

Mit ihm sieht wie folgt aus :

#include <memory> 
#include <cassert> 

template<class Base, class Derived> 
struct create_t 
{ 
    auto create() 
    { 
     return std::make_unique<Derived>(); 
    } 
}; 

struct base 
{ 
    virtual void print() const noexcept 
    { 
     std::cout << "base\n"; 
    } 
}; 

struct derived : public base 
{ 
    virtual void print() const noexcept override 
    { 
     std::cout << "derived\n"; 
    } 
}; 

int main() 
{ 
    factory<create_t, base, derived> f; 
    auto d = f.create<derived>(); 
    d->print(); 
} 

Während dies unter 2015 VC++ kompiliert wird GCC5.1 mir diesen Fehler geben aufgrund der noexcept Spezifikation von create():

..\main.cpp|20|error: cannot call member function 'auto 
create_t<T>::create() [with T = derived]' without object| 

Wie kann ich dies kompilieren?

Antwort

0
std::unique_ptr<Base> create() noexcept(noexcept(std::declval<CreatePolicy<Base, T>&>().create())) 

live example.

Sie erhalten nur die implizite this-> innerhalb des Körpers der Methode. Msvc erhält die Template-Erweiterung regelmäßig falsch, daher nehme ich sie für schuldig an, es sei denn, das Gegenteil wird bewiesen.

+1

Gibt es einen Grund, warum dies von GCC andere als abgelehnt wird, dass er einen Fehler hat? Es sieht wie gültiges C++ aus. Bei der Instantiierung sollte es in einen impliziten Klassenmember-Zugriff umgewandelt werden. –

+0

@joha Ich weiß keinen Grund, warum ein implizites 'this->' in diesem Kontext angenommen würde. Das passiert normalerweise nur in Körpern von Mitgliedsfunktionen. MSVC Template Instanziierungscode ist ziemlich skurril und nicht konform, also würde ich annehmen, dass sie wie gewöhnlich vermasselt sind. – Yakk

+0

Das Implizite Dies sollte hinzugefügt werden, wo auch immer "this" verwendet werden kann, und es sollte hinzugefügt werden, wenn die Vorlage im Instanziierungskontext instanziiert wird (Nachschlagen, da dieses Teil in letzter Zeit aufgrund von Defekten häufig geändert wurde). Also ein implizites sollte hier IMHO hinzugefügt werden. Die Transformation findet in allen "members" (auch NSDMIs) statt, also auch in excepts, da "this" dort verwendet werden kann und der Code zu diesem Zeitpunkt gültig ist, so dass der Compiler ihn zur Template-Definitionszeit nicht ablehnen kann. IMHO OPs Code ist gültig. –

1

Die Syntax base_class::method(...) zum Aufrufen einer Elementfunktion der Basisklasse funktioniert nur im Rumpf der Elementfunktionen. Dies schließt insbesondere die nicht bewerteten Kontexte aus, wie sie innerhalb der noexcept Spezifikation auftreten. Die Schönheit dieser Kontexte ist jedoch, dass sie genau das sind: Nicht bewertet. Du kannst also einfach eine Instanz deiner Klasse bekommen und die Methode aufrufen. Der üblicher Weg, dies zu tun ist mit std::declval:

std::unique_ptr<Base> create() noexcept(noexcept(std::declval<CreatePolicy<Base, T>&>().create())) 
Verwandte Themen