I'm new with templates, specially with parameter pack and I wonder if I can get the first value from the pack.
For example the following code:
template <typename T, typename... Args>
bool register(Args... args) {
if (!Foo<T>(args..) {
assert(std::is_same_v<std::string, args...[0]>);
std::cerr << "Failed call Foo with " args...[0] "\n";
}
}
How do I really get the first value in args...
?
Worth to note that args..
. can contain different types (string, boolean, etc.)
CodePudding user response:
Simpler in your case seems to change your function into:
template <typename T, typename Arg, typename... Args>
bool register(Arg arg, Args... args) {
if (!Foo<T>(arg, args...) {
assert(std::is_same_v<std::string, Arg>);
std::cerr << "Failed call Foo with " arg "\n";
}
}
and from the assert, even
template <typename T, typename... Args>
bool register(const std::string& s, Args... args) {
if (!Foo<T>(s, args...) {
std::cerr << "Failed call Foo with " s "\n";
}
}
else <tuple>
provides some useful tools:
template <typename T, typename Arg, typename... Args>
bool register(Args... args) {
if (!Foo<T>(args...) {
assert(std::is_same_v<std::string,
std::tuple_element_t<0, std::tuple<Args...>>);
std::cerr << "Failed call Foo with "
std::get<0>(std::tie(args...)) "\n";
}
}
CodePudding user response:
You can use lambda to extract the first parameter:
template<typename T, typename... Args>
bool register(Args... args) {
if (!Foo<T>(args...)) {
auto& first = [](auto& first, ...) -> auto& { return first; }(args...);
static_assert(std::is_same_v<std::string,
std::remove_reference_t<decltype(first)>>);
std::cerr << "Failed call Foo with " first "\n";
}
}
CodePudding user response:
I normally use the solution described above, just add an explicit extra template parameter for the first parameter. If you cannot do that this also works :
#include <type_traits>
namespace details
{
template<typename type_t, typename... args_t>
struct deduce_first
{
using type = type_t;
};
}
template<typename... args_t>
using first_t = typename details::deduce_first<args_t...>::type;
template<typename... args_t>
bool register_f(args_t&&... args)
{
static_assert(std::is_same_v<first_t<args_t...>, bool>, "first argument should have type bool");
return true;
}
int main()
{
register_f(true, 1.0);
// register_f(1.0); <== does indeed not complie
return 0;
}