I need a template function that checks if the first value is among those that follow.
I thought I would try something like this but it doesn't work
template<class T, class U>
bool is_in_set(const T &t, const U &u) {
return t == u;
}
template<class T, class ...Args>
bool is_in_set(const T &t, Args...args) {
return false || is_in_set(t, args...);
}
It compiles but I got the following warning warning C4717 : 'is_in_set' : recursive on all control paths, function will cause runtime stack overflow
Can anyone help me to fix it and explain me why it doesn't work?
From C++17, you can write this function with a fold-expression, which is simpler than writing a recursive function with a base case.
template<class T, class ...Args>
bool is_in_set(T const & t, Args const & ...args)
{
return (... || (t == args));
}
And now you can call it like this.
is_in_set(1, 2, 3, 4); // false
is_in_set(1, 2, 1, 4); // true
Here's a demo
Considering your code, you're getting the warning because you have an infinite recursion on this line:
return false || is_in_set(t, args...); // infinite recursion here
Note that you're calling the function template recursively with exactly the same arguments. This means you'll recurse infinitely, and never reach the base case.
You can fix this by naming the second argument and taking the remaining arguments as a parameter pack.
template<class T, class U>
bool is_in_set(T const & t, U const &u)
{
return t == u;
}
template<class T, class U, class ...Args>
bool is_in_set(T const & t, U const & u, Args const &...args)
{
return is_in_set(t, u) || is_in_set(t, args...);
}
Here's a demo
Related
I've got a function
template<typename T, typename FuncT, typename ... Args>
static void Submit(Handle<T> handle, FuncT&& funcT, Args&& ... args);
Handle is a class that contains an index to the data inside some array. This data can be retrieved through a handle_cast function.
T& data = *handle_cast<T*>(handle);
I'm not going to cover this implementation, because it's not related to my question.
Handle<T> handle is the main handle to a resource. I'd like args to be a mix, sometimes it'd be a handle, sometimes a different data.
FuncT first argument is T& and the rest of the arguments might be either *handle_cast<Args*> if this argument is Handle<Some Type> or just Arg
I came out with this solution, but I'm not sure if it's correct or maybe it could be done easier.
template<typename T, typename FuncT, typename ... Args>
static void Submit(Handle<T> handle, FuncT&& funcT, Args&& ... args)
{
std::variant<Args...> v;
bool isHandle = std::visit([](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_base_of_v<HandleBase, T>) {
return true;
} return false;
}, v);
func(*handle_cast<T*>(handle), std::forward<Args>(isHandle ? *handle_cast<Args*>(args) : args)...);
}
Is this solution ok or it can be done easier/cleaner?
You may be looking for something like this (not tested):
// Cloned from the standard std::forward
template<typename T>
T&& maybe_handle_forward(typename std::remove_reference<T>::type& t ) noexcept {
return std::forward<T>(t);
}
template<typename T>
T& maybe_handle_forward(Handle<T> h) noexcept {
return *handle_cast<T*>(h);
}
Now you can write
func(*handle_cast<T*>(handle), maybe_handle_forward<Args>(args)...);
The function 'Process' is taking a variable number of arguments of variable type. To handle different cases, I have successfully overloaded it like this:
// general case
template <typename ...Types>
void Process( const Types&... items )
// single T
template <typename T>
void Process( const T& t )
// one or more of type NVP<>
template <typename T1, typename ...Types>
void Process( const NVP<T1>& nvp1, const NVP<Types>&... nvps )
What I want to do - but can't - is the following: I need an overload for cases with any number of leading arguments of a types ATT<> followed by any number of NVP<> like this:
// any number of leading Types ATT<> followed by any number of NVP<>
template <typename ...ATypes, typename ...BTypes>
void Process( const ATT<ATypes>&... atts, const NVP<BTypes>&... nvps )
At first you would think it should be 'easy' for a compiler to match this, if it can already do the other cases. There should be absolutely no ambiguity here!? However, the matching fails, no error messages, but the desired overload it is just ignored by the compiler.
Currently using VS2017 with /std:c++17
Notes:
1. It can, obviously, be done for one leading type ATT<T1> like this
// one leading Type ATT<T1>
template <typename T1, typename ...Types>
void Process( const ATT<T1>& a1, const Types&... remaining )
But for more than one, I need to do some ugly manual recursion. I really want to have the whole pack of leading ATT<...>.
2. I am aware that a leading parameter pack - of general types - always is ambiguous for matching, but for a specialization like ATT<ATypes>... no ambiguity should exist.
You could dispatch from the const Types&... overload based on if Types... matches ATT<T>..., NVP<U>....
The basic strategy here is finding the index of the last ATT<T>, forwarding everything as a tuple, then indexing with the appropriate index sequence to forward to another function where the ATT values and NVP values are in two tuples:
namespace detail {
template<class...>
struct get_split_index;
template<class T, class... Others>
struct get_split_index<T, Others...> {
static constexpr std::size_t i = -1;
};
template<class T, class... Others>
struct get_split_index<ATT<T>, Others...> {
static constexpr std::size_t next = get_split_index<Others...>::i;
static constexpr std::size_t i = next == -1 ? -1 : next + 1u;
};
template<class T, class... Others>
struct get_split_index<NVP<T>, Others...> {
// will be 0 if the rest are all NVP<T>, otherwise -1
static constexpr std::size_t i = get_split_index<Others...>::i;
};
template<>
struct get_split_index<> {
static constexpr std::size_t i = 0;
};
template<typename... ATypes, typename... BTypes, std::size_t... ATT_I, std::size_t... NVP_I>
void Process(const std::tuple<const ATT<ATypes>&...>& att, const std::tuple<const NVP<BTypes>&...>& nvp, std::index_sequence<ATT_I...>, std::index_sequence<NVP_I...>) {
// Use (std::get<ATT_I>(att)) and (std::get<NVP_I>(nvp))
// instead of (atts) and (nvps) that you would use in your
// supposed `void Process(const ATT<ATypes>&..., const NVP<BTypes>&...)`
}
template<typename... Types, std::size_t... ATT_I, std::size_t... NVP_I>
void ProcessDispatch(const std::tuple<Types...>& t, std::index_sequence<ATT_I...> att_i, std::index_sequence<NVP_I...> nvp_i) {
detail::Process(std::forward_as_tuple(std::get<ATT_I>(t)...), std::forward_as_tuple(std::get<NVP_I + sizeof...(ATT_I)>(t)...), att_i, nvp_i);
}
}
template <typename ...Types>
void Process( const Types&... items ) {
constexpr std::size_t split_index = detail::get_split_index<Types...>::i;
if constexpr (split_index != -1) {
// Might want to check `&& sizeof...(Types) != 0`
detail::ProcessDispatch(std::forward_as_tuple(items...), std::make_index_sequence<split_index>{}, std::make_index_sequence<sizeof...(Types) - split_index>{});
} else {
// general case
}
}
template <typename T>
void Process( const T& t ) {
// single T
}
template <typename T1, typename ...Types>
void Process( const NVP<T1>& nvp1, const NVP<Types>&... nvps ) {
// one or more of type NVP<>
// This can also be folded into `detail::Process`, checking
// `if constexpr (sizeof...(BTypes) == 0)`.
}
Believe you can use a struct to help you here. The compiler can't determine where one parameter pack stops and the other begins, consider:
foo(1, 2.0, '3', "45", 6.0f). The first parameter pack could be nothing, the first, all of them or none of the above. There is no particular reason to prefer one over another. So you can't make a function that accepts two variadics. What you can do, is to split it into two structs, and specify explicitly the arguments for the outer class.
template<typename... Args>
struct S
{
template<typename... Inner>
static void Process(const ATT<Args>&... atts, const NVP<Inner>&... nvps) {}
};
Example for usage:
ATT<double> a1;
ATT<long> a2;
NVP<int> n1;
NVP<const char*> n2;
S<double, long>::Process(a1, a2, n1, n2);
Another version could be by using the constructor. Here, you also get auto-deduction which is easier. Unfortunately, it only works from C++17 and above.
template<typename... Args>
struct S
{
std::tuple<ATT<Args>...> tup;
S(const ATT<Args>&... atts)
: tup(atts...)
{}
template<typename... Inner>
void Process(const NVP<Inner>&... nvps){}
};
template<typename... Args>
S(const ATT<Args>&... atts)->S<Args...>;
And the usage is:
S(ATT(1), ATT(3.4)).Process(NVP("asdf"), NVP(3.4), NVP('f'));
return 0;
Assuming you're OK with getting them as tuples I made this after drawing from https://stackoverflow.com/a/12782697/1480324 :
#include <iostream>
#include <tuple>
template<typename T>
struct ATT {};
template<typename T>
struct NVP {};
template<typename... ATTs, typename... NVPs>
void Process(const std::tuple<ATT<ATTs>...>& atts, const std::tuple<NVP<NVPs>...>& nvps) {
std::cout << sizeof...(ATTs) << std::endl;
std::cout << sizeof...(NVPs) << std::endl;
}
int main() {
Process(std::make_tuple(ATT<int>(), ATT<double>()), std::make_tuple(NVP<std::string>(), NVP<bool>()));
return 0;
}
It compiles on https://www.onlinegdb.com/online_c++_compiler , but I can't test in visual studio.
Lately I wrote a template function to solve some code repetitions. It looks like this:
template<class T, class R, class... Args>
R call_or_throw(const std::weak_ptr<T>& ptr, const std::string& error, R (T::*fun)(Args...), Args... args) {
if (auto sp = ptr.lock())
{
return std::invoke(fun, *sp, args...);
}
else
{
throw std::runtime_error(error.c_str());
}
}
int main() {
auto a = std::make_shared<A>();
call_or_throw(std::weak_ptr<A>(a), "err", &A::foo, 1);
}
This code works perfectly well for class A which looks like this:
class A {
public:
void foo(int x) {
}
};
But fails to compile for one like this:
class A {
public:
void foo(const int& x) {
}
};
Why is it so (by why I mean why it fails to deduce the type) and how (if it is possible at all) can I make this code work with references?
Live example
Args types cannot be deduced both as const& (from fun parameter declaration) and non-reference from args declaration. A simple fix is to use two separate template type parameter packs:
template<class T, class R, class... Args, class... DeclaredArgs>
R call_or_throw(
const std::weak_ptr<T>& ptr,
const std::string& error,
R (T::*fun)(DeclaredArgs...),
Args... args);
As a downside, I can imagine slightly longer error messages in case of bad usage.
Note that the template parameter Args's type is deduced as const int& on the 3rd function argument &A::foo, and deduced as int on the 4th function parameter 1. They don't match and cause deduction fails.
You can exclude the 4th parameter from deduction, e.g.
template<class T, class R, class... Args>
R call_or_throw(const std::weak_ptr<T>& ptr,
const std::string& error,
R (T::*fun)(Args...),
std::type_identity_t<Args>... args) {
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
LIVE
PS: std::type_identity is supported since C++20; but it's quite easy to implement one.
Your issue is that you have conflict deductions for Args between:
R (T::*fun)(Args...)
Args... args
I suggest to have more generic code (no duplications between R (T::*fun)(Args...) and
const version R (T::*fun)(Args...) const and other alternative) with:
template<class T, class F, class... Args>
decltype(auto) call_or_throw(const std::weak_ptr<T>& ptr,
const std::string& error,
F f,
Args&&... args)
{
if (auto sp = ptr.lock())
{
return std::invoke(f, *sp, std::forward<Args>(args)...);
}
else
{
throw std::runtime_error(error.c_str());
}
}
I am writing a method to extract values from arbitrarily nested structs. I am almost there, but would like to also provide an option to convert the value retrieved (by default no conversion). Since parameter packs can't be followed by another template parameter, I have to fudge this a bit. The below works except for the indicated line:
#include <iostream>
#include <type_traits>
typedef struct {
int a;
int b;
} bar;
typedef struct {
int c;
bar d;
} baz;
template <typename T, typename S, typename... Ss>
auto inline getField(const T& obj, S field1, Ss... fields)
{
if constexpr (!sizeof...(fields))
return obj.*field1;
else
return getField(obj.*field1, fields...);
}
template <typename Obj, typename Out, class ...C, typename... T>
auto inline getFieldC(const Obj& obj, Out, T C::*... field)
{
return static_cast<Out>(getField(obj, field...));
}
template<class T> struct tag_t { using type = T; };
template<class...Ts>
using last = typename std::tuple_element_t< sizeof...(Ts) - 1, std::tuple<tag_t<Ts>...> >::type;
template <typename Obj, typename... T>
auto getMyFieldWrapper(const Obj& obj, T... field)
{
if constexpr (std::is_member_object_pointer_v<last<Obj, T...>>)
return getField(obj, field...);
else
return getFieldC(obj, last<Obj, T...>{}, field...); // <- this doesn't compile, need a way to pass all but last element of field
}
int main()
{
baz myObj;
std::cout << getMyFieldWrapper(myObj, &baz::c); // works
std::cout << getMyFieldWrapper(myObj, &baz::d, &bar::b); // works
std::cout << getMyFieldWrapper(myObj, &baz::d, &bar::b, 0.); // doesn't work
}
How do I implement the indicated line? I'm using the latest MSVC, and am happy to make full use of C++17 to keep things short and simple.
Usually more helpful to invert the flow. First, write a higher-order function that forwards an index sequence:
template <typename F, size_t... Is>
auto indices_impl(F f, std::index_sequence<Is...>) {
return f(std::integral_constant<size_t, Is>()...);
}
template <size_t N, typename F>
auto indices(F f) {
return indices_impl(f, std::make_index_sequence<N>());
}
That is just generally useful in lots of places.
In this case, we use it to write a higher-order function to drop the last element in a pack:
template <typename F, typename... Ts>
auto drop_last(F f, Ts... ts) {
return indices<sizeof...(Ts)-1>([&](auto... Is){
auto tuple = std::make_tuple(ts...);
return f(std::get<Is>(tuple)...);
});
}
And then you can use that:
return drop_last([&](auto... elems){
return getMyField(obj, last<Obj, T...>{}, elems...);
}, field...);
References omitted for brevity.
Of course, if you want to combine both and just rotate, you can do:
// Given f and some args t0, t1, ..., tn, calls f(tn, t0, t1, ..., tn-1)
template <typename F, typename... Ts>
auto rotate_right(F f, Ts... ts) {
auto tuple = std::make_tuple(ts...);
return indices<sizeof...(Ts)-1>([&](auto... Is){
return f(
std::get<sizeof...(Ts)-1>(tuple),
std::get<Is>(tuple)...);
});
}
used as:
return rotate_right([&](auto... elems){
return getMyField(obj, elems...);
}, field...);
How do I implement the indicated line?
Not sure to understand what do you want but... it seems to me that you can make it calling an intermediate function
template <std::size_t ... Is, typename ... Ts>
auto noLastArg (std::index_sequence<Is...> const &,
std::tuple<Ts...> const & tpl)
{ return getMyField(std::get<Is>(tpl)...); }
you can rewrite your function as follows
template <typename Obj, typename ... T>
auto getMyFieldWrapper (Obj const & obj, T ... field)
{
if constexpr (std::is_member_object_pointer<last<Obj, T...>>::value )
return getMyField(obj, field...);
else
return noLastArg(std::make_index_sequence<sizeof...(T)>{},
std::make_tuple(obj, field...));
}
The idea is pack the arguments for getMyField in a std::tuple of sizeof...(T)+1u elements (+1 because there is also obj) and call getMyField() unpacking the first sizeof...(T) of them.
But isn't clear, to me, if you want also last<Obj, T...>{}.
In this case, the call to noLastArg() become
return noLastArg(std::make_index_sequence<sizeof...(T)+1u>{},
std::make_tuple(obj, last<Obj, T...>{}, field...));
I am experimenting with C++ recursive templates and I do not know why my template is not working.
Say I want to define a recursive function that takes a variable number of arguments (for different types).
I've have looked at many examples of variadic templates, and all that I've seen so far use a separate template specialisation to specify the base case.
However, I think it would be nicer (in some cases at least) to use a single template, that defines the base case as well as the recursive cases.
I think this approach is especially nice if you have a lot of common logic in the function, which you would have to duplicate for your base case instance (exact same code in two different places).
The second template in the example below is supposed to be my solution. I would think that this template should be functioning on it's own. However this is not the case.
Without the first template, the code does not compile:
error: no matching function for call to
'add_elems'
return head[i] + add_elems(i, second, tail...);
^~~~~~~~~
in instantiation of function
template specialization 'add_elems<double, std::__1::vector<double, std::__1::allocator<double> >>' requested here
...
Apparently the template braks when tail consists of just one parameter. But shouldn't add_elems(i, second, tail...) then still be valid for the template
template<typename V, typename S, typename... T>
V add_elems(size_t i, const std::vector<V>& head, const S& second, const T&... tail) with an empty tail?
I do not know if this is compiler dependent, but I am using clang.
#include <iostream>
#include <vector>
/* This template is the exact same as the below template with an
empty parameter pack as tail. I want my code to be working
without this specialisation */
template<typename V, typename S>
V add_elems(size_t i, const std::vector<V>& head, const S& second)
{
/* Imagine some more code here */
return head[i] + second[i];
}
template<typename V, typename S, typename... T>
V add_elems(size_t i, const std::vector<V>& head, const S& second, const T&... tail)
{
/* Imagine some more code here (the same as above) */
if (sizeof...(tail) > 0)
return head[i] + add_elems(i, second, tail...);
else
return head[i] + second[i];
}
int main()
{
std::vector<double> a({1, -3, -3});
std::vector<double> b({2, -2, 1});
std::vector<double> c({4, -4, -11});
std::vector<double> d({4, 10, 0});
std::cout << "Result: " << add_elems(0, a, b, c, d);
std::cout << " ," << add_elems(1, a, b, c, d);
std::cout << " ," << add_elems(2, a, b, c, d);
}
The problem is that your if statement is not constexpr. Meaning that all code paths need to be compilable for every potential call to add_elems
This means that eventually you end up at a case where tail is just one element, and the compiler needs to evaluate add_elems(size_t&, const, std::vector<double>&), which doesn't exist because there's no second argument.
If you were able to have a constexpr if statement, then this would all work nicely because the compiler wouldn't even compile the bad branch when it evaluates to false, and therefore wouldn't look for a nonexistent function:
template<typename V, typename S, typename... T>
V add_elems(size_t i, const std::vector<V>& head, const S& second, const T&... tail)
{
if constexpr (sizeof...(tail) > 0)
return head[i] + add_elems(i, second, tail...);
else
return head[i] + second[i];
}
Demo (requires Clang 3.9.1 or greater and -std=c++1z option.)
For what it's worth, if you have access to C++17, you can achieve this with a unary right fold:
template<typename... T>
decltype(auto) add_elems(size_t i, const T&... elems)
{
return (elems[i] + ...);
}
Demo 2 (requires Clang 3.6.0 or greater and -std=c++1z option.)
Waiting for C++17, I propose a C++11 not-so-nice solution, following the AndyG one
template <typename T0, typename ... T>
auto add_elems2 (size_t i, T0 const & elem0, T const & ... elems)
-> decltype(elem0[i])
{
using unused=int[];
auto ret = elem0[i];
unused a { (ret += elems[i], 0)... };
return ret;
}
As the error message says, the problem you have at the moment is that the call add_elems(i, second, tail...) doesn't match the definition of the function, in the case where tail is empty. Even though the boolean expression in the if statement is constexpr, until c++1z the whole body of the function has to be valid.
#AndyG provides one way that c++1z can deal with this issue, another is with if constexpr, which allows a "compile time branch". Either of those allow you to have one (primary) specialisation of your template.
// Only in c++1z
template<typename V, typename S, typename... T>
V add_elems(size_t i, const std::vector<V>& head, const S& second, const T&... tail)
{
/* Imagine some more code here (the same as above) */
if constexpr (sizeof...(tail) > 0)
return head[i] + add_elems(i, second, tail...); // this is not required to be valid when the if is false
else
return head[i] + second[i]; // this is not required to be valid when the if is true (but it is happens to be valid anyway)
}
You can use Boost.Hana to emulate the behaviour of if constexpr in C++14. For example:
template <typename...>
struct is_empty_pack : hana::integral_constant<bool, false> {};
template <>
struct is_empty_pack<> : hana::integral_constant<bool, true> {};
template <typename T, typename... Ts>
auto sum(T const& t, Ts const&... ts) {
return hana::if_(is_empty_pack<Ts...>{},
[](auto const& t) { return t; },
[](auto const& t, auto const&... ts) { return t + sum(ts...); }
)(t, ts...);
}
As many have noted, this is easy in C++1z. It can be done in C++14, it is just hard.
template<class True, class False>
True pick( std::true_type, True t, False ) {
return std::move(t);
}
template<class True, class False>
False pick( std::false_type, True, False f ) {
return std::move(f);
}
template<bool b>
constexpr std::integral_constant<bool, b> bool_k;
template<typename V, typename S, typename... T>
V add_elems(size_t i, const std::vector<V>& head, const S& second, const T&... tail)
{
return
pick( bool_k<(sizeof...(tail)>0)>,
[&](const auto&... tail)->V{
// tail... template argument hides function argument above:
return head[i] + add_elems(i, second, tail...);
},
[&]()->V{
return head[i] + second[i];
}
)
( tail... );
};
we do a compile time dispatch using pick to one of two lambdas.
These lambdas take the part of the code that varies by auto parameter, which makes them templates. So long as they are valid for some set of auto parameters (even ones they are "never called with"), they are legal C++.
What we have readly done is hide the two overloads within the lambdas. As C++11 doesn't have template lambdas, this "hidden overload" technique won't work in C++11.