2017-12-14 1 views
0

Angenommen, ich habe einige Strukturen und jedes von ihnen hält eine enum als Mitglied. Ich möchte ein Verfahren zur Herstellung einer Struktur nennen, aber je nach einem Mitglied Struktur, wie im Codeb.:Wie man Schablone durch das Mitglied der Struktur ableitet

#include <iostream> 
#include <string> 
#include <type_traits> 

enum class Type{ 
    lowercase = 0, 
    uppercase 
}; 

struct Low{ 
    static constexpr Type cp = Type::lowercase; 
}; 

struct Up{ 
    static constexpr Type cp = Type::uppercase; 
}; 


template<typename Case, typename=void> 
struct Printer 
{ 
    void print_g(const std::string& s){ 
     std::cout << "just s: " << s << std::endl; 
    } 
}; 

template<typename X> 
struct Printer<X, std::enable_if_t<X::cp == Type::lowercase, void>> 
{ 
    void print_g(const std::string& s){ 
     std::cout << "lowercase " << std::nouppercase << s << std::endl; 
    } 
}; 

template<typename X> 
struct Printer <X, std::enable_if_t<X::cp == Type::uppercase, void>> 
{ 
    void print_g(const std::string& s){ 
     std::cout << "uppercase " << std::uppercase << s << std::endl; 
    } 
}; 

int main() 
{ 
    Printer<Low> pl; 
    pl.print_g("hello1"); 
    Printer<Up> p2; 
    p2.print_g("hello2"); 
} 

Aber diese Lösung sieht nicht ganz elegant zu mir. Vor allem der Teil typname = void in der ersten Vorlage. Nur dann kompiliert Code. Warum ist das der Fall? Und gibt es eine bessere (elegantere) Lösung für diese Template-Spezialisierung?

Antwort

1

In C++ 17, können Sie if constexpr verwenden:

template <typename X> 
struct Printer 
{ 
    void print_g(const std::string& s) 
    { 
     if constexpr(X::cp == Type::lowercase) 
     { 
      std::cout << "lowercase " << std::nouppercase << s << std::endl; 
     } 
     else if constexpr(X::cp == Type::uppercase) 
     { 
      std::cout << "uppercase " << std::uppercase << s << std::endl; 
     } 
     else 
     { 
      std::cout << "just s: " << s << std::endl; 
     } 
    } 
}; 

Wenn Sie Zugriff auf C 17 nicht über ++, betrachten Sie diese Optionen:

  • Verwenden Sie einen regelmäßigen if. .. else Aussage. Es gibt keinen Code, der in Ihrem Beispiel bedingt kompiliert werden muss.

  • Implementieren Sie static_if in C++ 14. Hier ist ein Gespräch, das ich das gab erklärt, wie es geht: Implementing static control flow in C++14

+0

Nizza :) Vielen Dank! – anicicn

+0

Und gibt es C++ 14 Weg das zu tun? Da bin ich irgendwie mit Compiler-Version beschränkt. – anicicn

+0

@anicicn: In Ihrem speziellen Fall können Sie eine normale "if" -Anweisung verwenden. –

1

Sie können fully specializePrinter für Low und Up.

template<class Case> 
struct Printer 
{ 
    void print_g(const std::string& s) { 
     std::cout << "just s: " << s << std::endl; 
    } 
}; 

template<> 
struct Printer<Low> 
{ 
    void print_g(const std::string& s) { 
     std::cout << "lowercase " << std::nouppercase << s << std::endl; 
    } 
}; 

template<> 
struct Printer<Up> 
{ 
    void print_g(const std::string& s) { 
     std::cout << "uppercase " << std::uppercase << s << std::endl; 
    } 
}; 

Beachten Sie, dass die Enum überhaupt nicht ins Spiel kommt. Wenn Sie sich für das Enum spezialisieren müssen, können Sie das auch tun.

template<Type Case> 
struct PrinterHelper 
{ 
    void print_g(const std::string& s) { 
     std::cout << "just s: " << s << std::endl; 
    } 
}; 

template<> 
struct PrinterHelper<Type::lowercase> 
{ 
    void print_g(const std::string& s) { 
     std::cout << "lowercase " << std::nouppercase << s << std::endl; 
    } 
}; 

template<> 
struct PrinterHelper<Type::uppercase> 
{ 
    void print_g(const std::string& s) { 
     std::cout << "uppercase " << std::uppercase << s << std::endl; 
    } 
}; 

template<class Case> 
using Printer = PrinterHelper<Case::cp>; 
1

würde ich wahrscheinlich mit gehen Sie einfach:

enum struct Casing 
{ 
    Lower, 
     Upper 
}; 
template<Casing> 
struct printer; 
template<> 
struct printer<Casing::Lower> 
{ 
    ... 
}; 
template<> 
struct printer<Casing::Upper> 
{ 
... 
}; 
Verwandte Themen