Home > Mobile >  Assigning function to function pointer with template parameter
Assigning function to function pointer with template parameter

Time:05-04

So I have these two functions:

bool intComp(int a, int b)
{
    return a > b;
}

bool stringComp(std::string a, std::string b)
{
    return strcmp(a.c_str(), b.c_str()) > 0;
}

And in my sort function I want to assign either the stringComp or intComp function:

template<typename T>
void sort(std::vector<T>& vector)
{
    bool (*compare)(T a, T b);

    if (typeid(T) == typeid(int))
    {
        compare = &intComp;
    }
    else if (typeid(T) == typeid(std::string))
    {
        compare = &stringComp;
    }
    ...
}

The assignment and sorting works fine when I remove the else if block with compare = &stringComp. But as soon as I try to assign functions with types other than int (for instance string) I get the following compiler error: '=': cannot convert from 'bool (__cdecl *)(std::string,std::string)' to 'bool (__cdecl *)(T,T)' What am I doing wrong? And why does the code work with int but not with other types? Do templates maybe work with integers under the hood similar to enums and that's why I can assign the intComp function without issues?

CodePudding user response:

The problem is that all branches of a normal if need to be valid at compile time, but only one of the branches in yours is. If T is int, then compare = &stringComp is invalid. If T is std::string, then compare = &intComp is invalid.

Instead, you need if constexpr, which was introduced in C 17 and does its comparison at compile time. It discards branches that it doesn't take as long as it's dependent on a template parameter, so it doesn't matter if they don't make sense for that type. For example:

template <typename T>
void sort(std::vector<T>& vector)
{
    bool (*compare)(T a, T b);

    if constexpr (std::is_same_v<T, int>) {
        compare = &intComp;
    } else if constexpr (std::is_same_v<T, std::string>) {
        compare = &stringComp;
    } else {
        // Error
    }

    // ...
}

CodePudding user response:

In C 17 you can use constexpr if:

#include <string>
#include <vector>
#include <typeinfo>

bool intComp(int a, int b) { return a < b; }

bool stringComp(std::string a, std::string b) { return a < b; }

template<typename T>
void sort(std::vector<T>& vector)
{
    bool (*compare)(T a, T b);

    if constexpr (typeid(T) == typeid(int))
    {
        compare = &intComp;
    }
    else if (typeid(T) == typeid(std::string))
    {
        compare = &stringComp;
    }
    
}

Before, and I'd actually use it in C 17 and beyond, you can let overload resolution pick the right function:

#include <string>
#include <vector>
#include <iostream>

bool Comp(int a, int b) { return a < b; }

bool Comp(std::string a, std::string b) { return a < b; }

template<typename T>
void sort(std::vector<T>& vector)
{
    if (vector.size() > 1) {
        std::cout << Comp(vector[0],vector[1]);
    }        
}
  • Related