Rames
Rames

Reputation: 938

Ambiguous call to variadic template function

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.

Upvotes: 0

Views: 330

Answers (4)

spraetor
spraetor

Reputation: 451

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).

Upvotes: 1

Puppy
Puppy

Reputation: 147036

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

Upvotes: 1

Cubic
Cubic

Reputation: 15703

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.

Upvotes: 0

Lingxi
Lingxi

Reputation: 14987

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';

Upvotes: 1

Related Questions