Вопрос

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;
}
Это было полезно?

Решение

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.

Другие советы

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

You want something like:

template <template <typename T> class IntegerType>
void Run_Algorithm // ...
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top