1

I have a class that holds various algorithms:

class Algorithm{

Algorithm()=delete;

public:
    template <typename IntegerType> 
    static IntegerType One(IntegerType a, IntegerType b);

    template <typename IntegerType> 
    static IntegerType Two(IntegerType a, IntegerType b);

    template <typename IntegerType> 
    static IntegerType Three(IntegerType a, IntegerType b);

    // ...
};

They can be called the following way:

int main(){

    Algorithm::One(35,68);
    Algorithm::Two(2344,65);
    //...
}

Now I want to make a function that will take any "Algorithm" function and perform the same steps before and after calling that function.
Here is what I have:

template <typename IntegerType>
void Run_Algorithm(std::function<IntegerType(IntegerType,IntegerType)>fun, IntegerType a, IntegerType b){
    //... stuff ...
    fun(a,b);
    //... stuff ...
    return;
}

When I try to call the function like this:

Run_Algorithm(Algorithm::One,1,1);

The error I get is:

cannot resolve overloaded function ‘One’ based on conversion to type ‘std::function<int(int, int)>’

How can I go about setting up a generic routine, that takes the desired algorithm as a parameter?

EDIT:
This solution worked as desired. It looks like this:

template <typename IntegerType>
void Run_Algorithm(IntegerType(*fun)(IntegerType, IntegerType), IntegerType a, IntegerType b){
    //... stuff ...
    fun(a,b);
    //... stuff ...
    return;
}
2
  • 1
    Algorithm looks like a namespace. Commented Sep 8, 2013 at 20:00
  • @MSalters I'd like it to be a namespace, but I don't want to allow access to certain sub-routines. Commented Sep 8, 2013 at 22:24

3 Answers 3

5

The name of a function template, like Algorithm::One, is treated like the name of a set of overloaded functions here. To select one of the overloads from that set, you need to put that name in a context where a specific function type (signature) is required. This is not possible with std::function, as it can take any argument in its ctor (with some "callable" requirements).

Additionally, using std::function as a parameter type is not required and not useful if the function is a template. It would just add an unnecessary type erasure and a level of indirection. The standard idiom of passing functions is:

template <typename Fun, typename IntegerType>
void Run_Algorithm(Fun fun, IntegerType a, IntegerType b);

But this doesn't help you selecting one overload of the overload set. You could select the overload at call site, as Dieter Lücking suggested, and then use this idiom.

However, you can provide an overload/alternatively:

template < typename IntegerType >
void Run_Algorithm(IntegerType(*)(IntegerType, IntegerType),
                   IntegerType, IntegerType);

which is more specialized and therefore preferred, if possible. Here, the function type is strictly IntegerType(IntegerType, IntegerType), therefore the compiler can select an overload of the overload set (from the name Algorithm::One).

Note: As per [temp.deduct.type]/5, IntegerType is in the first parameter in a non-deduced context for the argument Algorithm::One. Therefore, the second and third parameter are used to deduce IntegerType. After this deduction, the function type is fully specified and the overload can be selected.

The questions remain 1) if that's what you want and 2) if there's a better way to do what you intent to do.

Sign up to request clarification or add additional context in comments.

Comments

2

You need Algorithm::One< int > (not Algorithm::One) and thanks to ymett (Why can't my C++ compiler deduce template argument for boost function?):

template <class T> struct identity { typedef T type; };

template <typename IntegerType>
void Run_Algorithm(
    typename identity<
        std::function<IntegerType(IntegerType,IntegerType)>>::type fun,
    IntegerType a,
    IntegerType b)
{
}

int main() {
    Run_Algorithm(Algorithm::One<int>,1,1);
    return 0;
}

2 Comments

The identity is to put IntegerType in a non-deduced context for the first parameter of Run_Algorithm; otherwise the compiler would try (and fail) to deduce IntegerType from the first argument passed. It fails because the first argument is not a std::function here.
If you disambiguate (select the overload) at call site, you could as well use another template parameter instead of std::function (like template<class Fun, class Int> void Run_Algorithm(Fun, Int, Int);)
0

You want something like:

template <template <typename T> class IntegerType>
void Run_Algorithm // ...

1 Comment

Where would T get deduced? I'm not sure what the parameter list would look like here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.