2016-12-21 1 views
4

Ich versuche, eine Funktion zu schreiben, die eine Aufzählung von Werten auf eine Reihe von Typen basierend auf dem Laufzeitwert der Aufzählung abbildet. Ich weiß, dass Sie verschiedene Typen nicht basierend auf dem Laufzeitwert einer Enumeration zurückgeben können, da der Compiler nicht wissen, wie viel Stapelspeicherplatz zuzuordnen ist. Jedoch versuche ich dies als eine constexpr-Funktion zu schreiben, die die neue if-constexpr-Funktionalität verwendet, um dies zu implementieren.Können constexpr-if-else-Karosserien unterschiedliche Typen in der constexpr-Autofunktion zurückgeben?

Ich bekomme einen Fehler von clang beschweren, dass ich einen illegal angegebenen Template-Parameter verwende. Kann jemand sehen, wie man das umsetzt?

bearbeiten: Hier ist eine einfachere Version grok mein Problem prägnant mehr demonstriert: http://coliru.stacked-crooked.com/a/2b9fef340bd167a8

alten Code:

#include <cassert> 
#include <tuple> 
#include <type_traits> 

namespace 
{ 

enum class shape_type : std::size_t 
{ 
    TRIANGLE = 0u, 
    RECTANGLE, 
    POLYGON, 
    CUBE, 
    INVALID_SHAPE_TYPE 
}; 

template<std::size_t T> 
struct shape { 
}; 

using triangle = shape<static_cast<std::size_t>(shape_type::TRIANGLE)>; 
using rectangle = shape<static_cast<std::size_t>(shape_type::RECTANGLE)>; 
using polygon = shape<static_cast<std::size_t>(shape_type::POLYGON)>; 
using cube = shape<static_cast<std::size_t>(shape_type::CUBE)>; 

template<std::size_t A, std::size_t B> 
static bool constexpr same() noexcept { return A == B; } 

template<std::size_t ST> 
static auto constexpr make_impl(draw_mode const dm) 
{ 
    if constexpr (same<ST, shape_type::TRIANGLE>()) { 
    return triangle{}; 
    } else if (same<ST, shape_type::RECTANGLE>()) { 
    return rectangle{}; 
    } else if (same<ST, shape_type::POLYGON>()) { 
    return polygon{}; 
    } else if (same<ST, shape_type::CUBE>()) { 
    return cube{}; 
    } else { 
    assert(0 == 5); 
    } 
} 

static auto constexpr make(shape_type const st, draw_mode const dm) 
{ 
    switch (st) { 
     case shape_type::TRIANGLE: 
     return make_impl<shape_type::TRIANGLE>(dm); 
     case shape_type::RECTANGLE: 
     return make_impl<shape_type::RECTANGLE>(dm); 
     case shape_type::POLYGON: 
     return make_impl<shape_type::POLYGON>(dm); 
     case shape_type::CUBE: 
     return make_impl<shape_type::CUBE>(dm); 
     case shape_type::INVALID_SHAPE_TYPE: 
     assert(0 == 17); 
    } 
} 

} // ns anon 

//////////////////////////////////////////////////////////////////////////////////////////////////// 
// demo 
int main() 
{ 
} 

Fehler:

/home/benjamin/github/BoomHS/main.cxx:42:6: warning: constexpr if is a 
C++1z extension [-Wc++1z-extensions] 

if constexpr (same<ST, shape_type::TRIANGLE>()) { 
     ^/home/benjamin/github/BoomHS/main.cxx:59:16: error: no matching function for call to 'make_impl' 
     return make_impl<shape_type::TRIANGLE>(dm); 
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /home/benjamin/github/BoomHS/main.cxx:40:23: note: candidate template 
ignored: invalid explicitly-specified argument for template parameter 
'ST' static auto constexpr make_impl(draw_mode const dm) 
        ^/home/benjamin/github/BoomHS/main.cxx:61:16: error: no matching function for call to 'make_impl' 
     return make_impl<shape_type::RECTANGLE>(dm); 
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /home/benjamin/github/BoomHS/main.cxx:40:23: note: candidate template 
ignored: invalid explicitly-specified argument for template parameter 
'ST' static auto constexpr make_impl(draw_mode const dm) 
        ^/home/benjamin/github/BoomHS/main.cxx:63:16: error: no matching function for call to 'make_impl' 
     return make_impl<shape_type::POLYGON>(dm); 
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /home/benjamin/github/BoomHS/main.cxx:40:23: note: candidate template 
ignored: invalid explicitly-specified argument for template parameter 
'ST' static auto constexpr make_impl(draw_mode const dm) 
        ^/home/benjamin/github/BoomHS/main.cxx:65:16: error: no matching function for call to 'make_impl' 
     return make_impl<shape_type::CUBE>(dm); 
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~ /home/benjamin/github/BoomHS/main.cxx:40:23: note: candidate template 
ignored: invalid explicitly-specified argument for template parameter 
'ST' static auto constexpr make_impl(draw_mode const dm) 
+3

Was ist mit all den '' '' std :: size_t'''' in Ihren Template-Parameter? – mascoj

+0

das sieht nach einer überentwickelten Fabrikmethode aus. – Swift

+0

Ihr Fehler hat nichts mit 'if conexpr' zu tun (nicht dass Sie es richtig benutzen). –

Antwort

7

Ja, was Sie versuchen, ist erlaubt. Die beiden relevanten Auszüge ich in N4606 gefunden habe sind:

6.4.1/2 [stmt.if]

Wenn die if-Anweisung der Form ist, wenn constexpr [...] Wenn der Wert von die konvertierte Bedingung ist falsch, die erste Subanweisung ist eine verworfene Anweisung, andernfalls ist die zweite Subanweisung, falls vorhanden, eine verworfene Anweisung.

eine untaken Zweig in einem constexpr anzeigt, ob ein verworfen statment ist. Ferner Auto-Funktionen nicht verworfenen return-Anweisungen nur betrachten den Rückgabetyp für herzuleiten

7.1.7.4/2 [dcl.spec.auto] (Hervorhebung von mir)

[...] Wenn der deklarierte Der Rückgabetyp der Funktion enthält einen Platzhaltertyp. Der Rückgabetyp der Funktion ist , abgeleitet von nicht verworfenen Rücksendeanweisungen, falls vorhanden, im Hauptteil der Funktion (6.4.1).

Vereinfacht funktioniert der folgende Code sowohl für gcc als auch für clang head.

namespace { 

enum class shape_type { TRIANGLE, RECTANGLE, CIRCLE}; 

template<shape_type> 
struct shape { }; 

using triangle = shape<shape_type::TRIANGLE>; 
using rectangle = shape<shape_type::RECTANGLE>; 
using circle = shape<shape_type::CIRCLE>; 

template<shape_type ST> 
constexpr auto make() { 
    if constexpr (ST == shape_type::TRIANGLE) { 
    return triangle{}; 
    } else if constexpr (ST == shape_type::RECTANGLE) { 
    return rectangle{}; 
    } else if constexpr (ST == shape_type::CIRCLE) { 
    return circle{}; 
    } 
} 

} 

int main() { 
    auto t = make<shape_type::TRIANGLE>(); 
    auto r = make<shape_type::RECTANGLE>(); 
    auto c = make<shape_type::CIRCLE>(); 
} 
+0

@ T.C. verpasste einen conetexpr, aktualisiert für 3 Formen –

+0

Danke für die Antwort! Das ist fast das Gleiche, aber ich möchte den Typ in einer Variablen speichern können. Hier ist eine leicht modifizierte Version von Ihnen, um zu zeigen, was ich meine: http://coliru.stacked-crooked.com/a/2b9fef340bd167a8 – Short

+0

@Kurz können Sie den Typ in einem 'constexpr shape_type' speichern, der als Vorlage Argument –

Verwandte Themen