Ambiguous call to variadic template function - c++

I'm creating some classes which represent the functions in the mathematical meaning and their interface is to be 'math-friendly'. To accomplish this I want to create a variadic template operator() methods, which allow user to write defining functions in this way f(x, y) = 2*x + y; and then getting its value by calling f(4, 5);. I cannot predict the number of parameters (the number of variables in mathematical function) so I decided to use variadic templates. However overloading operator() twice as a variadic template and calling it causes the "ambigous call" error. Is there some way to overcome it, or do I have to create two seprate methods?
//expressions like f(x, y, z) = x*x+y-z
template <typename... Args>
RichFunction<T> &operator()(Args&&... args)
{
mMainLinears.clear();
setMainLinears(args...);
return *this;
}
//expressions like f(5, 4, 3)
template <typename... Args>
T operator()(Args&&... args)
{
Function<T>::assign(mMainLinears, 0, args...);
return Function<T>::value();
}
Edit: The whole background isn't very important. I only need to know how to overload variadic template method, where overloaded versions differ from each other only with arguments type.

Based on your description, I guess you need lambda expression more than variadic templates. For illustration:
auto f = [](double x, double y) { return 2 * x + y; };
std::cout << f(4, 5) << '\n';

You can SFINAE out one of the overloads if it does not meet whatever pre-requistes you want.

If I understand you correctly, the first operator() should define your mathematical expression and the second one should evaluate this expression defined previously.
To answer your question: you can not overload the method operator() in this way, since the signature in both methods is the same, i.e. exactly the same template definition and argumentlist. How should the compiler know which method to call? There must be a way to distinguish both calls.
Suggestions (1) for a solution
Probably you variable (x,y,z) are of some type. You could use the CRTP-pattern to define a common base class
template <class Sub>
struct Variable {};
struct X : Variable<X> {};
struct Y : Variable<Y> {}; //...
And then you could do an overload based on this class structure:
template <class... Xs>
ReturnType operator()(Variable<Xs>&&... vars) {...}
Inside of this method you can cast to the concrete variable type, e.g. by using static_cast<X&>(var) for a concrete argument of type Variable<X>& var.
Suggestion (2)
Use enable_if and disable_if (from boost, or std) to distinguish between the two argument types passed to the method, i.e.
template <class... Ts>
typename enable_if< is_scalar<Ts...>, ReturnType>::type
operator()(Ts&&... values) { ... }
template <class... Ts>
typename disable_if< is_scalar<Ts...>, ReturnType>::type
operator()(Ts&&... vars) { ... }
where is_scalar must be any meta-method that accepts variadic templates and defines a static boolean member value in the case that all types are scalars (number).

To the best of my knowledge, there is still no way to disambiguate methods by return value (you can disambiguate by template parameters though). You might wanna put the method to create a function into a separate object from the one that calls it if you want to keep the syntax.

Related

Is it possible to explicitly specify template arguments in a generic lambda passed to a function?

I want to create a compile-time loop over a small container (like 4-8 elements) with a size known at compile time.
It's not hard to create just one simple loop: I can create a template functor F with operator() overloaded and call it like in the code below
constexpr std::array<T, N> array{/*fill the array*/};
template <std::size_t index> struct F
{
void operator()()
{
std::vector<T> some_container{/*fill it in runtime*/};
some_container[index + some_offset] += std::get<index>(array); // Use safe array access
}
};
template <template<std::size_t> typename F, std::size_t... I>
void iterator_implementation(
const std::index_sequence<I...> /*unused*/)
{
((F<I>{}()), ...);
}
template <template<std::size_t> typename F>
void iterator()
{
iterator_implementation<F>(std::make_index_sequence<array.size()>{});
}
Though, if I want to create ten such loops and want to conveniently pass a bunch of references with it (closure), I should definitely use lambda functions.
In order to use std::get in the lambda, I should use generic lambdas.
So, the functor from the example below may become
auto f = [&some_container, some_offset]<std::size_t index>()
{
some_container[index + some_offset] += std::get<index>(array); // Use safe array access
};
I cannot simply pass this lambda to the iterator because it's impossible to pass a variable of a template type without specifying template parameters, and also I cannot simply get a type of the lambda and provide it as an F in order to call F<I>{} to recreate the lambda.
If I use typename F instead of template<std::size_t> typename F, I cannot call f<I> because typename has no template parameters, so cannot be used with them.
I can also pass std::get<index>(array) and index as ordinary arguments to the lambda function and avoid usage of template parameter but saving the safety of the access. Though, I wish to try using compile-time constants wherever it's possible in order to check how it works.
I believe that passing a compile-time constant numeric as a template argument may help the compiler to optimize my code more than if the number is an ordinary variable in my code (even though smart compiler should "see" this and optimize the call).
So, it's a question about new knowledge rather than discussing whether such an approach will help.
Is it possible to use generic lambda in a fold of parameter pack as I need?
P. S.
Despite the question title, it's not a duplicate of How to pass generic lambda into function because in my question template parameter should be specified explicitly, while in that question it can be deduced.
In a generic lambda, operator() is a template, but the lambda type is not.
Instead of instantiating a template at an index F<I>{}(), one needs to instantiate operator() at an index. Since the lambda has captures, one will need to pass it instead of just the type as a template argument.
Replace:
template <template<std::size_t> typename F, std::size_t... I>
void iterator_implementation(
const std::index_sequence<I...> /*unused*/)
{
((F<I>{}()), ...);
}
with:
template <typename F, std::size_t... I>
void iterator_implementation(F f,
const std::index_sequence<I...> /*unused*/)
{
((f.template operator()<I>()), ...);
}
Full example: https://godbolt.org/z/rYTP1KTYc

How to forward packed variadic arguments

I have a function that accepts variadic arguments packed into a tuple
template <class... Args>
void Bottom(tuple<Args&&...> t)
{
}
Is Args&& a forwarding reference? I.e. would the rules for reference collapsing apply or am I just appending && to every argument in the pack?
And say I want to call this function from a function that certainly gets forwarding references:
template <class... Args>
void Top(Args&&... args) {
// 1. Bottom<Pack...>();
// 2. Bottom<Pack&&...>();
}
which syntax would be best if I don't want to alter the arguments, 1 or 2?
EDIT
I'm only using tuple to showcase a class that packs my parameters. The actual packing classes vary in different levels of the call hierarchy. The idea of using using_fwd_as_tuple is cool as a resource to find what the library does at this case.
I'd say none. I'd use std::forward_as_tuple and let compiler do the deduction:
template <class... Args>
void Top(Args&&... args) {
Bottom(std::forward_as_tuple(args...));
}
No, tuple<Args&&...> t are not forwarding references. They can only be present as top-level arguments.
You are not appending anything, you are attempting to match the arguments. Such function only accepts tuples (by value) which contain r-value references.
Example
#include <tuple>
using namespace std;
template <class... Args>
void Bottom(tuple<Args&&...> t)
{
}
// Type your code here, or load an example.
int main(){
double var=0.0;
tuple<int,double&,char&&> tup1{1,var,'c'};
//#1
//Bottom(tup1);
tuple<int&&,double&&,char&&> tup2{1,0.0,'c'};
//#2
//Bottom(tup2);
//#3
Bottom(std::move(tup2));
}
Does not compile since the arguments cannot be matched.
Does not compile either. Eventhough the arguments do match, the tuple itself is passed by value, in this case by copy and the copy constructor is deleted in presence of r-value tuple members.
Moving is fine, this instantiates this template:
template<>
void Bottom<int, double, char>(std::tuple<int &&, double &&, char &&> t)
{
}

SFINAE with functions and emulating partial template specialization

I am trying to make a function X that specializes when a member function Y is provided and if the member function Y is not provided the function X uses the global non member function Y to achieve the same effect.
I am currently trying to achieve this with the following code
template <typename Container, typename std::enable_if_t<std::is_same<
decltype(std::declval<Container>().y()),
decltype(std::declval<Container>().y())>::value>* = nullptr>
void do_something(Container&& container) {
return std::forward<Container>().y();
}
template <typename Container, typename std::enable_if_t<!std::is_same<
decltype(std::declval<Container>().y()),
decltype(std::declval<Container>().y())>::value>* = nullptr>
void do_something(Container&& container) {
return y(std::forward<Container>(container);
}
But in the case when the container has both a member function y and the global non member function y also works on it. There is a compile error because for the second version of the function the template argument is ill formed because a member function y is needed.
Any idea how I can go about resolving this issue?
NOTE: This is different from just detecting whether a class has a function of a given signature. Sorry if the question seems to ask that! The accepted answer below should make my intention clearer.
The typical approach is to dispatch to a pair of functions where one is preferred if your condition is met and the other is simply a fallback. The nice thing is you don't even need enable_if, just the trailing decltype:
template <class C>
auto do_something_impl(C&& c, int)
-> decltype(std::forward<C>(c).y())
{
return std::forward<C>(c).y();
}
template <class C>
auto do_something_impl(C&& c, ...)
-> decltype(y(std::forward<C>(c))
{
return y(std::forward<C>(c));
}
And now just pass in 0:
template <class C>
auto do_something(C&& c)
-> decltype(do_something_impl(std::forward<C>(c), 0))
{
return do_something_impl(std::forward<C>(c), 0);
}
The conversion sequence to int is better than the one to ..., so if the type has the member function you want, that overload will be preferred even if both are viable candidates.

Function signatures in C++ templates

The std::function class is templated in such a way that when we want it to wrap a function like the following:
void printInt(int integer)
{
std::cout << int << '\n';
}
We use a std::function<void(int)>. Until recently I thought this was an odd nuance of the class, but a class I found while searching for delegate implementation in C++ uses a similar syntax.
What exactly is void(int), and what do we call it in technical terms? It seems to be the standard way of saying "a function that takes an int, and returns void" in codespeak, but my gut instinct says that's horribly oversimplified.
Secondly, I've noticed that when I see templates using this syntax they use variadic templates to allow multiple function signatures to be matched. From the link above:
template <typename T> class delegate;
template<class R, class ...A>
class delegate<R (A...)>
{
...
What is the reason for declaring the function as such instead of simply using the following:
template<class R, class ...A>
class delegate
{
...
The template parameter to std::function<Signature> is simply the type of a function, i.e., its signature. It uses the same notation as any function declaration except that it isn't named and the name is left out. You may have come across function pointers which use the same notation but the function signature is used for a pointer.
The reason std::function<Signature> (and apparently delegate<Signature>) are implemented using template specialization is to yield a nicer type:
template <typename T> class function;
template <typename R, typename... Args>
class function {
public:
R operator()(Args...);
// ...
};
template <typename R, typename... Args>
class other {
public:
R operator()(Args...);
// ...
};
int main() {
function<int(double, char)> f;
other<int, double, char> o;
}
Since the primary template for function<T> takes one type as argument, using the specialization the argument can be a normal function type. On the other hand, the same isn't done for other<T...> which, thus, gets a list of types.
It is worth nothing that std::function<T> objects can be passed around quite easily without any need to deal with many template arguments: since the function's signature is just a type, this class template takes just one template argument.

Determine signatures of overloaded member functions

Given some_type with a member function f it is possible to determine f's signature like this (and say let us place it in a tuple):
template <typename R, typename T, typename... A>
std::tuple<R, A...> signature_of_impl(R (T::*)(A...));
template <typename T>
using signature_of_member_f = decltype(signature_of_impl(&T::f));
struct some_type
{
int f(char, float);
};
using some_type_f_signature = signture_of_member_f<some_type>;
This obviously fails badly if f is overloaded. Is it possible to determine signatures of all existing overloads of f within some_type?
You can "ask" the compiler for the type of a specific function.
But there's no reflection in C++, you can't query what functions or even overloads of the same function exist in a class.