Nicht Art Schablone Konstanten Einwickeln zu vermeiden Parameter gleichen Typs Misch

stimmen
1

Ich habe ein Template-Methode nicht Typ Vorlage Argumente nehmen. Er hat die folgende Form:

template <long long connectionTimeout, long long sendTimeout, bool autoAck>
void create() { ... }

Es ist eine Hilfsfunktion in einem anderen Header, und das, was in dem Anrufer Code ärgert ich ist, dass die Konstanten nicht eingegeben werden.

Das heißt, statt diese Weise der Berufung:

create<1, 2, true>();

Ich ziehe folgendes haben:

create<
    connection_timeout {1},
    send_timeout {2},
    auto_ack {true}
>();

Mit der createFunktion garantiert , daß ein send_timeoutnicht anstelle eines weitergegeben werden connection_timeout.

Ich begann ein Proof of Concept zu schreiben, jedoch mit einigen Lücken. ++ 14.11 Ich mag es mit C arbeiten. Allerdings hatte ich C ++ 17-Konstrukte (siehe Code) zu verwenden, um die Dinge bis jetzt zu arbeiten. Aber sagen, dass ich nichts dagegen, C ++ 17-Lösungen um eine Idee zu bekommen, wenn dies getan werden kann.

Was fehlt in der folgenden ist die Kompilierung zu prüfen, ob die Typen übereinstimmen. Allerdings ist die Syntax in dem Haupt, was ich haben will.

#include <iostream>
#include <string>

template <typename T, T userSpecifiedValue>
struct compile_time_constant_wrapper
{
   using type = T;
   static const T defaultValue = userSpecifiedValue;

   constexpr operator T() const
   {
       return value;
   }

   T value = defaultValue;
};

using connection_timeout = compile_time_constant_wrapper<long long, 5000>;
using send_timeout = compile_time_constant_wrapper<long long, 10>;
using auto_ack = compile_time_constant_wrapper<bool, false>;

struct ComplicatedToBuild
{
    long long connectionTimeout;
    long long sendTimeout;
    bool autoAck;
};

template <typename T, 
          long long connectionTimeout = connection_timeout {} /*-std=c++17*/,
          long long sendTimeout = send_timeout {} /*-std=c++17*/,
          bool autoAck = auto_ack {} /*-std=c++17*/>
struct create
{
    operator T() const
    {
        return T{connectionTimeout, sendTimeout, autoAck};
    }
};

std::ostream& operator<<(std::ostream& out, const ComplicatedToBuild& complicated)
{
    out << connection timeout =  << complicated.connectionTimeout << , 
        << send timeout =  << complicated.sendTimeout << , 
        << auto ack =  << complicated.autoAck;
    return out;
}

int main()
{
    ComplicatedToBuild defaultValuesCase = create<ComplicatedToBuild>();
    std::cout << defaultValuesCase:  << defaultValuesCase << std::endl;

    ComplicatedToBuild customizedCase = create<
           ComplicatedToBuild,
           connection_timeout {2500},
           send_timeout {5},
           auto_ack {true}
    >();
    std::cout << customizedCase:  << customizedCase << std::endl;

    ComplicatedToBuild compilationErrorCase = create<
           ComplicatedToBuild,
           send_timeout {5},
           connection_timeout {2500},
           auto_ack {true}
    >();
}

In meinem Fall die Klasse ComplicatedToBuildist nicht eine einfache Struktur. Und die Werte benötigt es sind dafür bekannt , bei der Kompilierung zu bauen. Aus diesem Grund dachte ich nicht Typ Vorlagen.

Veröffentlicht am 27/11/2018 um 18:00
quelle vom benutzer
In anderen Sprachen...                            


2 antworten

stimmen
3

Hier ist eine Lösung, die eine etwas andere Syntax erreicht:

create<
    connection_timeout<1>,
    send_timeout<2>,
    auto_ack<true>
>();

Erstens brauchen wir einen is_instantiation_ofHelfer:

template <typename T, template <auto...> class C>
struct is_instantiation_of_impl : std::false_type { };

template <auto... Ts, template <auto...> class C>
struct is_instantiation_of_impl<C<Ts...>, C>  : std::true_type { };

template <typename T, template <auto...> class C>
constexpr bool is_instantiation_of = is_instantiation_of_impl<T, C>::value;

Dann können wir unseren „starken typedefs“ als Klassen definieren , die von erben std::integral_constant:

template <long long X>
struct connection_timeout : std::integral_constant<long long, X> { };

template <long long X>
struct send_timeout : std::integral_constant<long long, X> { };

template <bool X>
struct auto_ack : std::integral_constant<bool, X> { };

Schließlich wird unsere Schnittstelle wie folgt aussehen:

template <typename ConnectionTimeout,
          typename SendTimeout,
          typename AutoAck>
auto create()
    -> std::enable_if_t<
        is_instantiation_of<ConnectionTimeout, connection_timeout> 
     && is_instantiation_of<SendTimeout, send_timeout>
     && is_instantiation_of<AutoAck, auto_ack>
    >
{
}

leben Beispiel auf godbolt.org


Mit einer dramatischen Schnittstelle ändern, kann der Code viel einfacher sein:

template <long long A, long long B, bool C>
auto create(connection_timeout<A>, send_timeout<B>, auto_ack<C>)
{
}

int main()
{
    create(
        connection_timeout<1>{},
        send_timeout<2>{},
        auto_ack<true>{}
    );
}
Beantwortet am 27/11/2018 um 18:12
quelle vom benutzer

stimmen
4

#include <type_traits>    

enum class connection_timeout : long long {};
enum class send_timeout : long long {};
enum class auto_ack : bool {};

struct ComplicatedToBuild
{
    long long connectionTimeout;
    long long sendTimeout;
    bool autoAck;
};

template <typename T
        , connection_timeout connectionTimeout = connection_timeout{5000}
        , send_timeout sendTimeout = send_timeout{10}
        , auto_ack autoAck = auto_ack{false}>
T create()
{
    return {std::underlying_type_t<connection_timeout>(connectionTimeout)
          , std::underlying_type_t<send_timeout>(sendTimeout)
          , std::underlying_type_t<auto_ack>(autoAck)};
}

create<ComplicatedToBuild,
         connection_timeout{2500},
         send_timeout{5}, 
         auto_ack{true}>();

DEMO


Alternativ kann statt einen Fehler der Anhebung auf Argument / Parameter Typ stimmt nicht überein, können Sie erlauben Argumente in beliebiger Reihenfolge angegeben werden:

#include <tuple>

template <typename T, auto Arg, auto... Args>
T create()
{
    auto t = std::make_tuple(Arg, Args...);
    return {
         std::underlying_type_t<connection_timeout>(std::get<connection_timeout>(t))
       , std::underlying_type_t<send_timeout>(std::get<send_timeout>(t))
       , std::underlying_type_t<auto_ack>(std::get<auto_ack>(t))
    };
}

template <typename T>
T create()
{
    return create<T, connection_timeout{5000}, send_timeout{10}, auto_ack{false}>();
}

create<ComplicatedToBuild,
         connection_timeout{2500},
         send_timeout{5},
         auto_ack{true}>();    

create<ComplicatedToBuild,
         auto_ack{true},
         send_timeout{5},
         connection_timeout{2500}>();

DEMO 2

Beantwortet am 27/11/2018 um 18:50
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more