2017-06-15 3 views
2

Unten sind zwei weitgehend identische Vorlagen PgmArray und PgmArrayF. Der erste arbeitet für lvalue-ref Template-Parameter, der zweite arbeitet für integrale Parameter. Ich möchte diese beiden zu einem kombinieren:Kombinieren Sie zwei fast identische Klassenvorlagen

#include <stdint.h> 
#include <type_traits> 
#include <array> 
#include <iostream> 

template<typename T, const T&... Ts> 
struct PgmArray final { 
    static constexpr uint8_t size = sizeof... (Ts); 
    static constexpr T data[] {Ts...}; 
}; 

template<typename T, T... Ts> 
struct PgmArrayF final { 
    static constexpr uint8_t size = sizeof... (Ts); 
    static constexpr T data[] {Ts...}; 
}; 

struct A{ 
    uint8_t m = 0; 
}; 

constexpr A a1{1}; 
constexpr A a2{2}; 

constexpr auto x1 = PgmArray<A, a1, a2>{}; // ok 
constexpr auto x2 = PgmArrayF<int, 1, 2>{}; // ok 

//constexpr auto x3 = PgmArrayF<A, a1, a2>{}; // nok 
//constexpr auto x4 = PgmArray<int, 1, 2>{}; // nok 

int main() { 
} 

Antwort

2

Lassen Sie uns gerade umgekehrt, was @bolov tat und legte die Manipulation in den Typ des Parameters Pack:

// separate alias template not strictly necessary, but easier for readability 
template<class T> 
using maybe_cref = std::conditional_t<std::is_integral_v<T>, T, const T&>; 

template <typename T, maybe_cref<T>... Ts> 
struct PgmArray final { 
    static constexpr uint8_t size = sizeof... (Ts); 
    static constexpr T data[] {Ts...}; 
}; 
+0

Ausgezeichnet! Leider erzeugt dies ICE mit g ++> = 8.0 (g ++ 7.1 ist in Ordnung). – wimalopaan

6

Es ist nicht weniger Code, aber mehr wartbar, wenn Sie PgmArray oft ändern.

template<typename T, T... Ts> 
struct PgmArray final { 
    static constexpr uint8_t size = sizeof... (Ts); 
    static constexpr std::decay_t<T> data[] {Ts...}; 
}; 

template<typename T> 
struct MakePgmArray { 
    using TemplateArgument = typename std::conditional_t< 
      std::is_integral_v<T>, T, const T&>; 
    template<TemplateArgument... Ts> 
    using type = PgmArray<TemplateArgument, Ts...>; 
}; 

... 

constexpr auto x1 = MakePgmArray<A>::type<a1, a2>{}; // ok 
constexpr auto x2 = MakePgmArray<int>::type<1, 2>{}; // ok 
5

Inspiriert von petersohn's answer

könnten Sie auch dies tun:

template <typename U, U... Ts> 
struct PgmArray final { 
    using T = std::remove_const_t<std::remove_reference_t<U>>; 

    static constexpr uint8_t size = sizeof... (Ts); 
    static constexpr T data[] {Ts...}; 
}; 

constexpr auto x3 = PgmArray<const A&, a1, a2>{}; // ok 
constexpr auto x4 = PgmArray<int, 1, 2>{}; // ok 
+0

Das war der, den ich zuerst ausprobiert habe, aber ich fand es umständlich, 'PgmArray auszusagen, deshalb habe ich th erstellt e 'MakePgmArray' struct, um das Rauschen auf diese Weise zu verringern (Hinzufügen eines weiteren Rauschens als Nebeneffekt). – petersohn

+0

Idealerweise könnte man einen 'constexpr' make-helfer' make_pgm_array (1, 2, 3) 'schreiben, der ein' PgmArray erzeugt. Aber ich denke, das ist unmöglich, wenn man nicht mehr wie 'std: : interger_constant' – wimalopaan

+0

@Wimalopaan benutzerdefinierte Literale können vom Typ Integer-Konstante sein. – Yakk

Verwandte Themen