简体   繁体   中英

C++ Only accept a set of types for template parameter pack

To limit a template parameter pack to a certain type, this can be done in the following way:

    std::enable_if_t<std::conjunction_v<std::is_same<int32_t, Ts>...>>
    send(bool condition, Ts...);

I would actually allow int32_t and std::string and any order.

How can this be expressed?

I had a workaround using a variant, but this does not look so nice to me:

    using allowed_types = std::variant<int32_t, std::string>;
    template<typename... Ts>
    std::enable_if_t<std::conjunction_v<std::is_assignable<allowed_types, Ts>...>>
    send(bool condition, Ts...);

And this does not compile:

    std::enable_if_t<std::conjunction_v<std::is_same<int32_t, Ts> || std::is_same<std::string, Ts>...>> // <- does not compile!
    send(bool condition, Ts...);

You are using std::conjunction as a replacement for && on the std::bool_constant level correctly, but then you should in the same way replace || with std::disjunction :

std::enable_if_t<std::conjunction_v<std::disjunction<std::is_same<int32_t, Ts>, std::is_same<std::string, Ts>>...>>

or with C++17 you can use fold expressions on the level of bool values instead:

std::enable_if_t<((std::is_same_v<int32_t, Ts> || std::is_same_v<std::string, Ts>) && ...)>>

(Outer parentheses are required by the fold expression syntax.)

Of course with C++20 this can be done much nicer with the help of concepts:

template<typename T>
concept Int32OrString = std::same_as<T, int32_t> || std::same_as<T, std::string>;

void send(bool condition, Int32OrString auto...);

or even

template<typename T, typename... Ts>
concept AnyOf = (std::same_as<T, Ts> || ...);

void send(bool condition, AnyOf<int32_t, std::string> auto...);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM