C++ overloaded function as template argument

后端 未结 4 683
生来不讨喜
生来不讨喜 2020-12-03 14:40

the simplified version of my code is here

int foo(int x)
{
  return x;
}

int foo(int x, int y)
{
  return x+y;
}

template
int ba         


        
相关标签:
4条回答
  • 2020-12-03 15:14

    Yes:

    bar(3, static_cast<int(*)(int)>(&foo));
    

    or:

    bar<int(*)(int)>(3, &foo);
    
    0 讨论(0)
  • 2020-12-03 15:20

    You can give an explicit template argument:

    bar<int(int)>(3, foo);
    

    or cast the ambiguous function name to a type from which the template argument can be deduced:

    bar(3, static_cast<int(*)(int)>(foo));
    

    or wrap it in another function (or function object) to remove the ambiguity

    bar(3, [](int x){return foo(x);});
    
    0 讨论(0)
  • 2020-12-03 15:21

    I handle this problem with the following macro:

    #define LIFT(fname) \
    [] (auto&&... args) -> decltype (auto) \
    { \
        return fname (std::forward <decltype (args)> (args)...); \
    }
    

    Given your definitions of foo and bar, you can say

    int main()
    {
        bar(3, LIFT(foo));
        return 0;
    }
    

    and the correct overload will be selected. This uses some features of C++14, namely generic lambdas and decltype(auto). If you're using C++11, you can get more or less the same effect with a little more work:

    #define DECLARE_LIFTABLE(NAME) \
    struct NAME##_lifter \
    { \
        template <typename... Args> \
        auto operator () (Args&&... args) -> decltype (NAME (std::forward <Args> (args)...)) \
        { \
            return NAME (std::forward <decltype (args)> (args)...); \
        } \
    }
    #define LIFT(NAME) (NAME##_lifter {})
    
    DECLARE_LIFTABLE(foo);
    int main()
    {
        bar(3, LIFT(foo));
        return 0;
    }
    

    If you're using C++98, you're basically stuck with a cast to the appropriate function pointer type.

    0 讨论(0)
  • 2020-12-03 15:24

    No, you can't, because you are calling the function always with only one argument, you need a type with only one argument. Instead, you can use template by value (no typename or class)

    One argument:

    
    int foo(int x)
    {
        return x;
    }
    
    int foo(int x, int y)
    {
        return x+y;
    }
    
    typedef int (*foo_fcn)(int);
    
    template<foo_fcn unary_func>
    int bar(int k)
    {
        return unary_func(k);
    }
    
    int main()
    {
        bar<foo>(3);
        return 0;
    }
    
    

    Two arguments:

    
    int foo(int x)
    {
        return x;
    }
    
    int foo(int x, int y)
    {
        return x+y;
    }
    
    typedef int (*foo_fcn)(int, int);
    
    template<foo_fcn unary_func>
    int bar(int k)
    {
        return unary_func(k, k);
    }
    
    int main()
    {
        bar<foo>(3);
        return 0;
    }
    
    

    Both:

    
    int foo(int x) // first foo
    {
        return x;
    }
    
    int foo(int x, int y) // second foo
    {
        return x+y;
    }
    
    typedef int (*foo_fcn)(int);
    typedef int (*foo_fcn_2)(int, int);
    
    template<foo_fcn unary_func>
    int bar(int k)
    {
        return unary_func(k);
    }
    
    template<foo_fcn_2 unary_func>
    int bar(int a, int b)
    {
        return unary_func(a, b);
    }
    
    
    int main()
    {
        bar<foo>(3,1); // compiler will choose first foo
        bar<foo>(4); // compiler will choose second foo
        return 0;
    }
    
    0 讨论(0)
提交回复
热议问题