C++ Multiple function parameters with varargs of a specific type [duplicate]
Asked Answered
C

2

2

I am relatively new to C++ coming from a Java background so I am not sure if the functionality I am looking for is directly possible.

I am attempting to create a C++ function that accepts two different parameters but with the following requirements: The first parameter is a single input object of a specific type and the second parameter is a variable list of additional objects all of the which are the same type as the first parameter.

I am specifically looking for something similar to this Java code (if possible).

public static <E> boolean func(E input, E... args) {}

If this is not possible, does anyone know of some sort of implementation to make this to work for strings specifically? Something along the lines of:

bool func(std::string input, std::string... args) {}

I have researched this topic a bit and found that function templates might be able to help here, but I am unsure on how to support multiple parameter types (of the same datatype) using this approach.

My initial line of thinking was to try something like this:

template<class... T>
bool func(const T input, const T&... args) {}

But this only accounts for the varargs parameter type, not the first parameter.

Any help/advice is greatly appreciated. Thanks in advance.

Context answered 4/4, 2022 at 7:31 Comment(1)
How about template <typename T> bool func(std::initializer_list<T>);. (requires extra {} at call site). (see std::max (3/4) as example).Gamber
T
2

You need to define two templates types, one for the input and one for the parameter pack.

The function would then look like this:

template <typename T, typename ... Ts>
bool func(const T & input, const Ts & ... args);

To guarantee all the types are the same, we can combine std::conjunction with std::is_same.

We can also make use of static_assert so that we can generate an error at compile time if the condition is not satisfied.
It allows us to provide a custom error message so that the error would be clearer and easier for the user to understand.

It would then become:

template <typename T, typename ... Ts>
bool func(const T & input, const Ts & ... args)
{
    static_assert(std::conjunction_v<std::is_same<T, Ts>...>, "Error: All parameters must be of the same type.");

    //...

    return true;
}

You could also use std::enable_if instead of static_assert.

I personally prefer to use static_assert because we can make the error more explicit. If we use std::enable_if, in case of failure, the user will still need to check on his/her own what was the evaluated condition to find out what was wrong.

In that case, the function would be like:

template <typename T, typename ... Ts>
std::enable_if_t<std::conjunction_v<std::is_same<T, Ts>...>, bool>
func(const T & input, const Ts & ... args)
{
    //...

    return true;
}
Telepathy answered 4/4, 2022 at 8:7 Comment(2)
The use of static_assert has one downside though: It restricts the ability to overload the function because the static_assert triggers a compiler error after overload resolution. std::enable_if (SFINAE in general) removes the candidate before overload resolutions. So other overloads may get a chance to be selected.Zenaidazenana
@JakobStark Good point ! I'm not sure OP intended to overload the function (or it's not mentioned in the question), but thank you for noticing it !Telepathy
Z
1

To my knowledge, there is no way to directly introduce a template parameter pack where all of the types are required to be the same.

However, you can easily create a template that matches different types at first, but SFINAE fails if the types do not match. The following example introduces SFINAE through the return type (that is the reason why the return type bool goes into that std::enable_if_t metafunction) and only provides a valid function candidate from the template if all the types match.

template<typename T, typename... Ts>
std::enable_if_t<(std::is_same_v<T, Ts> && ...), bool>
func(const T& input, const Ts&... args) {
    return true;
}

If you happen to be able to use C++20 concepts, you can write this in a more declarative way using a requires clause like in the following:

template<typename T, typename... Ts>
requires (std::is_same_v<T, Ts> && ...)
bool func(const T& input, const Ts&... args) {
    return true;
}
Zenaidazenana answered 4/4, 2022 at 7:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.